From 2fff02f4bcda3ee55d365617174d9361bb01cb6f Mon Sep 17 00:00:00 2001 From: iseulde Date: Thu, 6 Dec 2018 18:24:14 +0100 Subject: [PATCH 01/15] RichText: List: use value to indent/outdent --- .../editor/src/components/rich-text/index.js | 2 + .../src/components/rich-text/list-edit.js | 53 +++++++- packages/rich-text/src/apply-line-format.js | 87 ++++++++++++ packages/rich-text/src/index.js | 1 + .../rich-text/src/test/apply-line-format.js | 125 ++++++++++++++++++ 5 files changed, 261 insertions(+), 7 deletions(-) create mode 100644 packages/rich-text/src/apply-line-format.js create mode 100644 packages/rich-text/src/test/apply-line-format.js diff --git a/packages/editor/src/components/rich-text/index.js b/packages/editor/src/components/rich-text/index.js index 72d86b84415566..1b2b97f18c350a 100644 --- a/packages/editor/src/components/rich-text/index.js +++ b/packages/editor/src/components/rich-text/index.js @@ -843,6 +843,8 @@ export class RichText extends Component { onTagNameChange={ onTagNameChange } tagName={ Tagname } onSyncDOM={ () => this.onChange( this.createRecord() ) } + value={ record } + onChange={ this.onChange } /> ) } { isSelected && ! inlineToolbar && ( diff --git a/packages/editor/src/components/rich-text/list-edit.js b/packages/editor/src/components/rich-text/list-edit.js index cb52fe688d7eff..5b50beb37ae5ff 100644 --- a/packages/editor/src/components/rich-text/list-edit.js +++ b/packages/editor/src/components/rich-text/list-edit.js @@ -5,6 +5,12 @@ import { Toolbar } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { Fragment } from '@wordpress/element'; +import { + LINE_SEPARATOR, + slice, + normaliseFormats, + applyLineFormat, +} from '@wordpress/rich-text'; /** * Internal dependencies @@ -35,7 +41,42 @@ function isActiveListType( editor, tagName, rootTagName ) { return list.nodeName.toLowerCase() === tagName; } -export const ListEdit = ( { editor, onTagNameChange, tagName, onSyncDOM } ) => ( +function getLineIndex( value ) { + const beforeValue = slice( value, 0, value.start ); + return beforeValue.text.lastIndexOf( LINE_SEPARATOR ); +} + +function outdentLineFormat( value ) { + const index = getLineIndex( value ); + const { text, formats, start, end } = value; + const newFormats = formats.slice( 0 ); + + if ( ! newFormats[ index ] ) { + return value; + } + + newFormats[ index ].pop(); + + if ( newFormats[ index ].length === 0 ) { + delete newFormats[ index ]; + } + + return normaliseFormats( { + text, + formats: newFormats, + start, + end, + } ); +} + +export const ListEdit = ( { + editor, + onTagNameChange, + tagName, + onSyncDOM, + value, + onChange, +} ) => ( ( { icon: 'editor-outdent', title: __( 'Outdent list item' ), - onClick() { - editor.execCommand( 'Outdent' ); - onSyncDOM(); + onClick: () => { + onChange( outdentLineFormat( value ) ); }, }, { icon: 'editor-indent', title: __( 'Indent list item' ), - onClick() { - editor.execCommand( 'Indent' ); - onSyncDOM(); + onClick: () => { + onChange( applyLineFormat( value, { type: 'ul' }, { type: tagName } ) ); }, }, ].filter( Boolean ) } diff --git a/packages/rich-text/src/apply-line-format.js b/packages/rich-text/src/apply-line-format.js new file mode 100644 index 00000000000000..b95068c5dafb5b --- /dev/null +++ b/packages/rich-text/src/apply-line-format.js @@ -0,0 +1,87 @@ +/** + * Internal dependencies + */ + +import { LINE_SEPARATOR } from './special-characters'; +import { normaliseFormats } from './normalise-formats'; + +function getLineIndex( { start, text }, startIndex = start ) { + let index = startIndex; + + while ( index-- ) { + if ( text[ index ] === LINE_SEPARATOR ) { + return index; + } + } +} + +function getTargetFormats( + { text, formats }, + startIndex, + formatCount, +) { + let index = startIndex; + + while ( index-- ) { + if ( text[ index ] !== LINE_SEPARATOR ) { + continue; + } + + if ( ! formats[ index ] ) { + return []; + } + + if ( formats[ index ].length === formatCount + 1 ) { + return formats[ index ]; + } else if ( formats[ index ].length === formatCount ) { + return formats[ index ]; + } + } + + return []; +} + +export function applyLineFormat( value, format, rootFormat ) { + const lineIndex = getLineIndex( value ); + + if ( lineIndex === undefined ) { + return value; + } + + const { text, formats, start, end } = value; + const formatsAtLineIndex = formats[ lineIndex ] || []; + const targetFormatCount = formatsAtLineIndex.length; + const targetFormats = getTargetFormats( value, lineIndex, targetFormatCount ); + const previousLineIndex = getLineIndex( value, lineIndex ); + const formatsAtPreviousLineIndex = formats[ previousLineIndex ] || []; + + if ( formatsAtLineIndex.length > formatsAtPreviousLineIndex.length ) { + return value; + } + + const newFormats = formats.slice(); + + for ( let index = lineIndex; index < end; index++ ) { + if ( text[ index ] !== LINE_SEPARATOR ) { + continue; + } + + if ( targetFormats.length === formatsAtLineIndex.length ) { + const lastformat = targetFormats[ targetFormats.length - 1 ] || rootFormat; + + newFormats[ index ] = targetFormats.concat( + [ lastformat ], + ( newFormats[ index ] || [] ).slice( targetFormats.length ) + ); + } else { + newFormats[ index ] = targetFormats; + } + } + + return normaliseFormats( { + text, + formats: newFormats, + start, + end, + } ); +} diff --git a/packages/rich-text/src/index.js b/packages/rich-text/src/index.js index 61e6475dc778a6..984a3b8f9258bf 100644 --- a/packages/rich-text/src/index.js +++ b/packages/rich-text/src/index.js @@ -1,6 +1,7 @@ import './store'; export { applyFormat } from './apply-format'; +export { applyLineFormat } from './apply-line-format'; export { charAt } from './char-at'; export { concat } from './concat'; export { create } from './create'; diff --git a/packages/rich-text/src/test/apply-line-format.js b/packages/rich-text/src/test/apply-line-format.js new file mode 100644 index 00000000000000..57cc50c52fe726 --- /dev/null +++ b/packages/rich-text/src/test/apply-line-format.js @@ -0,0 +1,125 @@ +/** + * External dependencies + */ +import deepFreeze from 'deep-freeze'; + +/** + * Internal dependencies + */ + +import { applyLineFormat } from '../apply-line-format'; +import { getSparseArrayLength } from './helpers'; +import { LINE_SEPARATOR } from '../special-characters'; + +describe( 'applyFormat', () => { + const ul = { type: 'ul' }; + const ol = { type: 'ol' }; + + it( 'should not apply anything if there is only one line', () => { + const record = { + formats: [ , ], + text: '1', + start: 1, + end: 1, + }; + const result = applyLineFormat( deepFreeze( record ), ul, ul ); + + expect( result ).toEqual( record ); + expect( result ).toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 0 ); + } ); + + it( 'should apply line format', () => { + const record = { + formats: [ , , ], + text: `1${ LINE_SEPARATOR }`, + start: 2, + end: 2, + }; + const expected = { + formats: [ , [ ul ] ], + text: `1${ LINE_SEPARATOR }`, + start: 2, + end: 2, + }; + const result = applyLineFormat( deepFreeze( record ), ul, ul ); + + expect( result ).toEqual( expected ); + expect( result ).not.toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 1 ); + } ); + + it( 'should not apply additional line format', () => { + const record = { + formats: [ , [ ul ] ], + text: `1${ LINE_SEPARATOR }`, + start: 2, + end: 2, + }; + const result = applyLineFormat( deepFreeze( record ), ul, ul ); + + expect( result ).toEqual( record ); + expect( result ).toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 1 ); + } ); + + it( 'should apply line format with previous line format', () => { + const record = { + formats: [ , [ ol ], , ], + text: `1${ LINE_SEPARATOR }${ LINE_SEPARATOR }`, + start: 3, + end: 3, + }; + const expected = { + formats: [ , [ ol ], [ ol ] ], + text: `1${ LINE_SEPARATOR }${ LINE_SEPARATOR }`, + start: 3, + end: 3, + }; + const result = applyLineFormat( deepFreeze( record ), ul, ul ); + + expect( result ).toEqual( expected ); + expect( result ).not.toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 2 ); + } ); + + it( 'should apply line format with existing', () => { + const record = { + formats: [ , [ ul ], , [ ul ], , ], + text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + start: 5, + end: 5, + }; + const expected = { + formats: [ , [ ul ], , [ ul, ul ], , ], + text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + start: 5, + end: 5, + }; + const result = applyLineFormat( deepFreeze( record ), ul, ul ); + + expect( result ).toEqual( expected ); + expect( result ).not.toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 2 ); + } ); + + it( 'should apply line format with multi select', () => { + const record = { + formats: [ , , , [ ul ], , ], + text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + start: 2, + end: 5, + }; + const expected = { + formats: [ , [ ul ], , [ ul, ul ], , ], + text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + start: 2, + end: 5, + }; + const result = applyLineFormat( deepFreeze( record ), ul, ul ); + + expect( result ).toEqual( expected ); + expect( result ).not.toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 2 ); + } ); +} ); From fffaa50382d2d15fa3a26f519d7a597613878e47 Mon Sep 17 00:00:00 2001 From: iseulde Date: Thu, 6 Dec 2018 19:12:15 +0100 Subject: [PATCH 02/15] Add outdent --- .../src/components/rich-text/list-edit.js | 46 ++------------- packages/rich-text/src/index.js | 1 + packages/rich-text/src/remove-line-format.js | 57 +++++++++++++++++++ 3 files changed, 64 insertions(+), 40 deletions(-) create mode 100644 packages/rich-text/src/remove-line-format.js diff --git a/packages/editor/src/components/rich-text/list-edit.js b/packages/editor/src/components/rich-text/list-edit.js index 5b50beb37ae5ff..569c700f6a2a69 100644 --- a/packages/editor/src/components/rich-text/list-edit.js +++ b/packages/editor/src/components/rich-text/list-edit.js @@ -6,10 +6,8 @@ import { Toolbar } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { Fragment } from '@wordpress/element'; import { - LINE_SEPARATOR, - slice, - normaliseFormats, applyLineFormat, + removeLineFormat, } from '@wordpress/rich-text'; /** @@ -41,34 +39,6 @@ function isActiveListType( editor, tagName, rootTagName ) { return list.nodeName.toLowerCase() === tagName; } -function getLineIndex( value ) { - const beforeValue = slice( value, 0, value.start ); - return beforeValue.text.lastIndexOf( LINE_SEPARATOR ); -} - -function outdentLineFormat( value ) { - const index = getLineIndex( value ); - const { text, formats, start, end } = value; - const newFormats = formats.slice( 0 ); - - if ( ! newFormats[ index ] ) { - return value; - } - - newFormats[ index ].pop(); - - if ( newFormats[ index ].length === 0 ) { - delete newFormats[ index ]; - } - - return normaliseFormats( { - text, - formats: newFormats, - start, - end, - } ); -} - export const ListEdit = ( { editor, onTagNameChange, @@ -82,32 +52,28 @@ export const ListEdit = ( { type="primary" character="[" onUse={ () => { - editor.execCommand( 'Outdent' ); - onSyncDOM(); + onChange( removeLineFormat( value ) ); } } /> { - editor.execCommand( 'Indent' ); - onSyncDOM(); + onChange( applyLineFormat( value, { type: 'ul' }, { type: tagName } ) ); } } /> { - editor.execCommand( 'Indent' ); - onSyncDOM(); + onChange( applyLineFormat( value, { type: 'ul' }, { type: tagName } ) ); } } /> { - editor.execCommand( 'Outdent' ); - onSyncDOM(); + onChange( removeLineFormat( value ) ); } } /> @@ -143,7 +109,7 @@ export const ListEdit = ( { icon: 'editor-outdent', title: __( 'Outdent list item' ), onClick: () => { - onChange( outdentLineFormat( value ) ); + onChange( removeLineFormat( value ) ); }, }, { diff --git a/packages/rich-text/src/index.js b/packages/rich-text/src/index.js index 984a3b8f9258bf..753600540b8271 100644 --- a/packages/rich-text/src/index.js +++ b/packages/rich-text/src/index.js @@ -14,6 +14,7 @@ export { isEmpty, isEmptyLine } from './is-empty'; export { join } from './join'; export { registerFormatType } from './register-format-type'; export { removeFormat } from './remove-format'; +export { removeLineFormat } from './remove-line-format'; export { remove } from './remove'; export { replace } from './replace'; export { insert } from './insert'; diff --git a/packages/rich-text/src/remove-line-format.js b/packages/rich-text/src/remove-line-format.js new file mode 100644 index 00000000000000..78fe2096c84f39 --- /dev/null +++ b/packages/rich-text/src/remove-line-format.js @@ -0,0 +1,57 @@ +/** + * Internal dependencies + */ + +import { LINE_SEPARATOR } from './special-characters'; +import { normaliseFormats } from './normalise-formats'; + +function getLineIndex( { start, text }, startIndex = start ) { + let index = startIndex; + + while ( index-- ) { + if ( text[ index ] === LINE_SEPARATOR ) { + return index; + } + } +} + +function getParentFormats( { text, formats }, startIndex, formatCount ) { + let index = startIndex; + + while ( index-- ) { + if ( text[ index ] !== LINE_SEPARATOR ) { + continue; + } + + const currentFormatCount = formats[ index ] ? formats[ index ].length : 0; + + if ( currentFormatCount === formatCount - 1 ) { + return formats[ index ]; + } + } +} + +export function removeLineFormat( value ) { + const { text, formats, start, end } = value; + const lineIndex = getLineIndex( value ); + const lineFormats = formats[ lineIndex ]; + + if ( lineFormats === undefined ) { + return value; + } + + const newFormats = formats.slice( 0 ); + + newFormats[ lineIndex ] = getParentFormats( value, lineIndex, lineFormats.length ); + + if ( newFormats[ lineIndex ] === undefined ) { + delete newFormats[ lineIndex ]; + } + + return normaliseFormats( { + text, + formats: newFormats, + start, + end, + } ); +} From 7d74d99ac73b18eab8dbe501e815d000ba8a4c57 Mon Sep 17 00:00:00 2001 From: iseulde Date: Thu, 6 Dec 2018 19:18:24 +0100 Subject: [PATCH 03/15] Support multi outdent --- packages/rich-text/src/remove-line-format.js | 23 +++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/rich-text/src/remove-line-format.js b/packages/rich-text/src/remove-line-format.js index 78fe2096c84f39..aa8bd6f1ec4373 100644 --- a/packages/rich-text/src/remove-line-format.js +++ b/packages/rich-text/src/remove-line-format.js @@ -23,12 +23,14 @@ function getParentFormats( { text, formats }, startIndex, formatCount ) { continue; } - const currentFormatCount = formats[ index ] ? formats[ index ].length : 0; + const formatsAtIndex = formats[ index ] || []; - if ( currentFormatCount === formatCount - 1 ) { - return formats[ index ]; + if ( formatsAtIndex.length === formatCount - 1 ) { + return formatsAtIndex; } } + + return []; } export function removeLineFormat( value ) { @@ -41,11 +43,20 @@ export function removeLineFormat( value ) { } const newFormats = formats.slice( 0 ); + const parentFormats = getParentFormats( value, lineIndex, lineFormats.length ); - newFormats[ lineIndex ] = getParentFormats( value, lineIndex, lineFormats.length ); + for ( let index = lineIndex; index < end; index++ ) { + if ( text[ index ] !== LINE_SEPARATOR ) { + continue; + } - if ( newFormats[ lineIndex ] === undefined ) { - delete newFormats[ lineIndex ]; + const trailingFormats = newFormats[ index ].slice( parentFormats.length + 1 ); + + newFormats[ index ] = parentFormats.concat( trailingFormats ); + + if ( newFormats[ index ].length === 0 ) { + delete newFormats[ lineIndex ]; + } } return normaliseFormats( { From 42f9d865593959c94994d65ff462bd16086fc696 Mon Sep 17 00:00:00 2001 From: iseulde Date: Thu, 6 Dec 2018 20:15:10 +0100 Subject: [PATCH 04/15] Hold one reference per format --- packages/rich-text/src/normalise-formats.js | 41 ++++++++++--------- .../rich-text/src/test/normalise-formats.js | 5 ++- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/packages/rich-text/src/normalise-formats.js b/packages/rich-text/src/normalise-formats.js index 349540df9dc256..533df66933886a 100644 --- a/packages/rich-text/src/normalise-formats.js +++ b/packages/rich-text/src/normalise-formats.js @@ -1,3 +1,9 @@ +/** + * External dependencies + */ + +import { find } from 'lodash'; + /** * Internal dependencies */ @@ -12,25 +18,22 @@ import { isFormatEqual } from './is-format-equal'; * @return {Object} New value with normalised formats. */ export function normaliseFormats( { formats, 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; - } - } ); + const refs = []; + const newFormats = formats.map( ( formatsAtIndex ) => + formatsAtIndex.map( ( format ) => { + const equalRef = find( refs, ( ref ) => + isFormatEqual( ref, format ) + ); + + if ( equalRef ) { + return equalRef; + } + + refs.push( format ); + + return format; + } ) + ); return { formats: newFormats, text, start, end }; } diff --git a/packages/rich-text/src/test/normalise-formats.js b/packages/rich-text/src/test/normalise-formats.js index 8984bcb17771b8..25525625f18b5d 100644 --- a/packages/rich-text/src/test/normalise-formats.js +++ b/packages/rich-text/src/test/normalise-formats.js @@ -16,16 +16,17 @@ describe( 'normaliseFormats', () => { it( 'should normalise formats', () => { const record = { - formats: [ , [ em ], [ { ...em }, { ...strong } ], [ em, strong ] ], + formats: [ , [ em ], [ { ...em }, { ...strong } ], [ em, strong ], , [ { ...em } ] ], text: 'one two three', }; const result = normaliseFormats( deepFreeze( record ) ); expect( result ).toEqual( record ); expect( result ).not.toBe( record ); - expect( getSparseArrayLength( result.formats ) ).toBe( 3 ); + expect( getSparseArrayLength( result.formats ) ).toBe( 4 ); expect( result.formats[ 1 ][ 0 ] ).toBe( result.formats[ 2 ][ 0 ] ); expect( result.formats[ 1 ][ 0 ] ).toBe( result.formats[ 3 ][ 0 ] ); + expect( result.formats[ 1 ][ 0 ] ).toBe( result.formats[ 5 ][ 0 ] ); expect( result.formats[ 2 ][ 1 ] ).toBe( result.formats[ 3 ][ 1 ] ); } ); } ); From 72e7c1567eb24ab3febd4a38d7f23ef69473f478 Mon Sep 17 00:00:00 2001 From: iseulde Date: Thu, 6 Dec 2018 20:34:43 +0100 Subject: [PATCH 05/15] Keep list formats when indenting to new index --- packages/rich-text/src/apply-line-format.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/rich-text/src/apply-line-format.js b/packages/rich-text/src/apply-line-format.js index b95068c5dafb5b..b108c4d2282d9b 100644 --- a/packages/rich-text/src/apply-line-format.js +++ b/packages/rich-text/src/apply-line-format.js @@ -50,8 +50,6 @@ export function applyLineFormat( value, format, rootFormat ) { const { text, formats, start, end } = value; const formatsAtLineIndex = formats[ lineIndex ] || []; - const targetFormatCount = formatsAtLineIndex.length; - const targetFormats = getTargetFormats( value, lineIndex, targetFormatCount ); const previousLineIndex = getLineIndex( value, lineIndex ); const formatsAtPreviousLineIndex = formats[ previousLineIndex ] || []; @@ -60,6 +58,8 @@ export function applyLineFormat( value, format, rootFormat ) { } const newFormats = formats.slice(); + const targetFormatCount = formatsAtLineIndex.length; + const targetFormats = getTargetFormats( value, lineIndex, targetFormatCount ); for ( let index = lineIndex; index < end; index++ ) { if ( text[ index ] !== LINE_SEPARATOR ) { @@ -74,7 +74,9 @@ export function applyLineFormat( value, format, rootFormat ) { ( newFormats[ index ] || [] ).slice( targetFormats.length ) ); } else { - newFormats[ index ] = targetFormats; + newFormats[ index ] = targetFormats.concat( + ( newFormats[ index ] || [] ).slice( targetFormats.length - 1 ) + ); } } From e768938dfeb18807ac59b5c562ac1331ddc8e2d5 Mon Sep 17 00:00:00 2001 From: iseulde Date: Thu, 6 Dec 2018 20:56:29 +0100 Subject: [PATCH 06/15] Remove unneeded parameter --- .../editor/src/components/rich-text/list-edit.js | 6 +++--- packages/rich-text/src/apply-line-format.js | 2 +- packages/rich-text/src/test/apply-line-format.js | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/editor/src/components/rich-text/list-edit.js b/packages/editor/src/components/rich-text/list-edit.js index 569c700f6a2a69..eaf446aaeef3e1 100644 --- a/packages/editor/src/components/rich-text/list-edit.js +++ b/packages/editor/src/components/rich-text/list-edit.js @@ -59,14 +59,14 @@ export const ListEdit = ( { type="primary" character="]" onUse={ () => { - onChange( applyLineFormat( value, { type: 'ul' }, { type: tagName } ) ); + onChange( applyLineFormat( value, { type: tagName } ) ); } } /> { - onChange( applyLineFormat( value, { type: 'ul' }, { type: tagName } ) ); + onChange( applyLineFormat( value, { type: tagName } ) ); } } /> { - onChange( applyLineFormat( value, { type: 'ul' }, { type: tagName } ) ); + onChange( applyLineFormat( value, { type: tagName } ) ); }, }, ].filter( Boolean ) } diff --git a/packages/rich-text/src/apply-line-format.js b/packages/rich-text/src/apply-line-format.js index b108c4d2282d9b..042f1f7838f58c 100644 --- a/packages/rich-text/src/apply-line-format.js +++ b/packages/rich-text/src/apply-line-format.js @@ -41,7 +41,7 @@ function getTargetFormats( return []; } -export function applyLineFormat( value, format, rootFormat ) { +export function applyLineFormat( value, rootFormat ) { const lineIndex = getLineIndex( value ); if ( lineIndex === undefined ) { diff --git a/packages/rich-text/src/test/apply-line-format.js b/packages/rich-text/src/test/apply-line-format.js index 57cc50c52fe726..32e17583eca92b 100644 --- a/packages/rich-text/src/test/apply-line-format.js +++ b/packages/rich-text/src/test/apply-line-format.js @@ -22,7 +22,7 @@ describe( 'applyFormat', () => { start: 1, end: 1, }; - const result = applyLineFormat( deepFreeze( record ), ul, ul ); + const result = applyLineFormat( deepFreeze( record ), ul ); expect( result ).toEqual( record ); expect( result ).toBe( record ); @@ -42,7 +42,7 @@ describe( 'applyFormat', () => { start: 2, end: 2, }; - const result = applyLineFormat( deepFreeze( record ), ul, ul ); + const result = applyLineFormat( deepFreeze( record ), ul ); expect( result ).toEqual( expected ); expect( result ).not.toBe( record ); @@ -56,7 +56,7 @@ describe( 'applyFormat', () => { start: 2, end: 2, }; - const result = applyLineFormat( deepFreeze( record ), ul, ul ); + const result = applyLineFormat( deepFreeze( record ), ul ); expect( result ).toEqual( record ); expect( result ).toBe( record ); @@ -76,7 +76,7 @@ describe( 'applyFormat', () => { start: 3, end: 3, }; - const result = applyLineFormat( deepFreeze( record ), ul, ul ); + const result = applyLineFormat( deepFreeze( record ), ul ); expect( result ).toEqual( expected ); expect( result ).not.toBe( record ); @@ -96,7 +96,7 @@ describe( 'applyFormat', () => { start: 5, end: 5, }; - const result = applyLineFormat( deepFreeze( record ), ul, ul ); + const result = applyLineFormat( deepFreeze( record ), ul ); expect( result ).toEqual( expected ); expect( result ).not.toBe( record ); @@ -116,7 +116,7 @@ describe( 'applyFormat', () => { start: 2, end: 5, }; - const result = applyLineFormat( deepFreeze( record ), ul, ul ); + const result = applyLineFormat( deepFreeze( record ), ul ); expect( result ).toEqual( expected ); expect( result ).not.toBe( record ); From c55934a69676a9e6060d43388d91ea449044061d Mon Sep 17 00:00:00 2001 From: iseulde Date: Thu, 6 Dec 2018 21:11:25 +0100 Subject: [PATCH 07/15] Rename --- .../src/components/rich-text/list-edit.js | 16 ++++++------ ...ly-line-format.js => indent-list-items.js} | 2 +- packages/rich-text/src/index.js | 4 +-- ...e-line-format.js => outdent-list-items.js} | 2 +- ...ly-line-format.js => indent-line-items.js} | 26 +++++++++---------- 5 files changed, 25 insertions(+), 25 deletions(-) rename packages/rich-text/src/{apply-line-format.js => indent-list-items.js} (97%) rename packages/rich-text/src/{remove-line-format.js => outdent-list-items.js} (96%) rename packages/rich-text/src/test/{apply-line-format.js => indent-line-items.js} (75%) diff --git a/packages/editor/src/components/rich-text/list-edit.js b/packages/editor/src/components/rich-text/list-edit.js index eaf446aaeef3e1..e88be44c58acc8 100644 --- a/packages/editor/src/components/rich-text/list-edit.js +++ b/packages/editor/src/components/rich-text/list-edit.js @@ -6,8 +6,8 @@ import { Toolbar } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { Fragment } from '@wordpress/element'; import { - applyLineFormat, - removeLineFormat, + indentListItems, + outdentListItems, } from '@wordpress/rich-text'; /** @@ -52,28 +52,28 @@ export const ListEdit = ( { type="primary" character="[" onUse={ () => { - onChange( removeLineFormat( value ) ); + onChange( outdentListItems( value ) ); } } /> { - onChange( applyLineFormat( value, { type: tagName } ) ); + onChange( indentListItems( value, { type: tagName } ) ); } } /> { - onChange( applyLineFormat( value, { type: tagName } ) ); + onChange( indentListItems( value, { type: tagName } ) ); } } /> { - onChange( removeLineFormat( value ) ); + onChange( outdentListItems( value ) ); } } /> @@ -109,14 +109,14 @@ export const ListEdit = ( { icon: 'editor-outdent', title: __( 'Outdent list item' ), onClick: () => { - onChange( removeLineFormat( value ) ); + onChange( outdentListItems( value ) ); }, }, { icon: 'editor-indent', title: __( 'Indent list item' ), onClick: () => { - onChange( applyLineFormat( value, { type: tagName } ) ); + onChange( indentListItems( value, { type: tagName } ) ); }, }, ].filter( Boolean ) } diff --git a/packages/rich-text/src/apply-line-format.js b/packages/rich-text/src/indent-list-items.js similarity index 97% rename from packages/rich-text/src/apply-line-format.js rename to packages/rich-text/src/indent-list-items.js index 042f1f7838f58c..8d736d84ff1d1f 100644 --- a/packages/rich-text/src/apply-line-format.js +++ b/packages/rich-text/src/indent-list-items.js @@ -41,7 +41,7 @@ function getTargetFormats( return []; } -export function applyLineFormat( value, rootFormat ) { +export function indentListItems( value, rootFormat ) { const lineIndex = getLineIndex( value ); if ( lineIndex === undefined ) { diff --git a/packages/rich-text/src/index.js b/packages/rich-text/src/index.js index 753600540b8271..712c1a609b3441 100644 --- a/packages/rich-text/src/index.js +++ b/packages/rich-text/src/index.js @@ -1,7 +1,6 @@ import './store'; export { applyFormat } from './apply-format'; -export { applyLineFormat } from './apply-line-format'; export { charAt } from './char-at'; export { concat } from './concat'; export { create } from './create'; @@ -14,7 +13,6 @@ export { isEmpty, isEmptyLine } from './is-empty'; export { join } from './join'; export { registerFormatType } from './register-format-type'; export { removeFormat } from './remove-format'; -export { removeLineFormat } from './remove-line-format'; export { remove } from './remove'; export { replace } from './replace'; export { insert } from './insert'; @@ -27,3 +25,5 @@ export { toHTMLString } from './to-html-string'; export { toggleFormat } from './toggle-format'; export { LINE_SEPARATOR } from './special-characters'; export { unregisterFormatType } from './unregister-format-type'; +export { indentListItems } from './indent-list-items'; +export { outdentListItems } from './outdent-list-items'; diff --git a/packages/rich-text/src/remove-line-format.js b/packages/rich-text/src/outdent-list-items.js similarity index 96% rename from packages/rich-text/src/remove-line-format.js rename to packages/rich-text/src/outdent-list-items.js index aa8bd6f1ec4373..e41b48c7d4fcf1 100644 --- a/packages/rich-text/src/remove-line-format.js +++ b/packages/rich-text/src/outdent-list-items.js @@ -33,7 +33,7 @@ function getParentFormats( { text, formats }, startIndex, formatCount ) { return []; } -export function removeLineFormat( value ) { +export function outdentListItems( value ) { const { text, formats, start, end } = value; const lineIndex = getLineIndex( value ); const lineFormats = formats[ lineIndex ]; diff --git a/packages/rich-text/src/test/apply-line-format.js b/packages/rich-text/src/test/indent-line-items.js similarity index 75% rename from packages/rich-text/src/test/apply-line-format.js rename to packages/rich-text/src/test/indent-line-items.js index 32e17583eca92b..e789f578fbb07a 100644 --- a/packages/rich-text/src/test/apply-line-format.js +++ b/packages/rich-text/src/test/indent-line-items.js @@ -7,7 +7,7 @@ import deepFreeze from 'deep-freeze'; * Internal dependencies */ -import { applyLineFormat } from '../apply-line-format'; +import { indentListItems } from '../indent-list-items'; import { getSparseArrayLength } from './helpers'; import { LINE_SEPARATOR } from '../special-characters'; @@ -15,21 +15,21 @@ describe( 'applyFormat', () => { const ul = { type: 'ul' }; const ol = { type: 'ol' }; - it( 'should not apply anything if there is only one line', () => { + it( 'should not indent only item', () => { const record = { formats: [ , ], text: '1', start: 1, end: 1, }; - const result = applyLineFormat( deepFreeze( record ), ul ); + const result = indentListItems( deepFreeze( record ), ul ); expect( result ).toEqual( record ); expect( result ).toBe( record ); expect( getSparseArrayLength( result.formats ) ).toBe( 0 ); } ); - it( 'should apply line format', () => { + it( 'should indent', () => { const record = { formats: [ , , ], text: `1${ LINE_SEPARATOR }`, @@ -42,28 +42,28 @@ describe( 'applyFormat', () => { start: 2, end: 2, }; - const result = applyLineFormat( deepFreeze( record ), ul ); + const result = indentListItems( deepFreeze( record ), ul ); expect( result ).toEqual( expected ); expect( result ).not.toBe( record ); expect( getSparseArrayLength( result.formats ) ).toBe( 1 ); } ); - it( 'should not apply additional line format', () => { + it( 'should not indent without target list', () => { const record = { formats: [ , [ ul ] ], text: `1${ LINE_SEPARATOR }`, start: 2, end: 2, }; - const result = applyLineFormat( deepFreeze( record ), ul ); + const result = indentListItems( deepFreeze( record ), ul ); expect( result ).toEqual( record ); expect( result ).toBe( record ); expect( getSparseArrayLength( result.formats ) ).toBe( 1 ); } ); - it( 'should apply line format with previous line format', () => { + it( 'should indent and merge with previous list', () => { const record = { formats: [ , [ ol ], , ], text: `1${ LINE_SEPARATOR }${ LINE_SEPARATOR }`, @@ -76,14 +76,14 @@ describe( 'applyFormat', () => { start: 3, end: 3, }; - const result = applyLineFormat( deepFreeze( record ), ul ); + const result = indentListItems( deepFreeze( record ), ul ); expect( result ).toEqual( expected ); expect( result ).not.toBe( record ); expect( getSparseArrayLength( result.formats ) ).toBe( 2 ); } ); - it( 'should apply line format with existing', () => { + it( 'should indent already indented item', () => { const record = { formats: [ , [ ul ], , [ ul ], , ], text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, @@ -96,14 +96,14 @@ describe( 'applyFormat', () => { start: 5, end: 5, }; - const result = applyLineFormat( deepFreeze( record ), ul ); + const result = indentListItems( deepFreeze( record ), ul ); expect( result ).toEqual( expected ); expect( result ).not.toBe( record ); expect( getSparseArrayLength( result.formats ) ).toBe( 2 ); } ); - it( 'should apply line format with multi select', () => { + it( 'should indent with multiple lines selected', () => { const record = { formats: [ , , , [ ul ], , ], text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, @@ -116,7 +116,7 @@ describe( 'applyFormat', () => { start: 2, end: 5, }; - const result = applyLineFormat( deepFreeze( record ), ul ); + const result = indentListItems( deepFreeze( record ), ul ); expect( result ).toEqual( expected ); expect( result ).not.toBe( record ); From 13139f3055ea28f633073572c82ffa5c850d1227 Mon Sep 17 00:00:00 2001 From: iseulde Date: Thu, 6 Dec 2018 22:27:02 +0100 Subject: [PATCH 08/15] Add logic to change list type --- lib/packages-dependencies.php | 2 +- .../editor/src/components/rich-text/index.js | 15 +---- .../src/components/rich-text/list-edit.js | 67 +++++++++++++------ .../src/components/rich-text/tinymce.js | 5 -- packages/rich-text/src/change-list-type.js | 53 +++++++++++++++ packages/rich-text/src/index.js | 1 + 6 files changed, 102 insertions(+), 41 deletions(-) create mode 100644 packages/rich-text/src/change-list-type.js diff --git a/lib/packages-dependencies.php b/lib/packages-dependencies.php index ece2a6ae2bb867..6d170f25f56152 100644 --- a/lib/packages-dependencies.php +++ b/lib/packages-dependencies.php @@ -133,7 +133,7 @@ ), 'wp-editor' => array( 'lodash', - 'wp-tinymce-lists', + 'wp-tinymce', 'wp-a11y', 'wp-api-fetch', 'wp-blob', diff --git a/packages/editor/src/components/rich-text/index.js b/packages/editor/src/components/rich-text/index.js index 1b2b97f18c350a..21ae5a91b5cac3 100644 --- a/packages/editor/src/components/rich-text/index.js +++ b/packages/editor/src/components/rich-text/index.js @@ -91,7 +91,6 @@ export class RichText extends Component { this.onSplit = this.props.unstableOnSplit; } - this.onSetup = this.onSetup.bind( this ); this.onFocus = this.onFocus.bind( this ); this.onBlur = this.onBlur.bind( this ); this.onChange = this.onChange.bind( this ); @@ -137,15 +136,6 @@ export class RichText extends Component { this.editableRef = node; } - /** - * Sets a reference to the TinyMCE editor instance. - * - * @param {Editor} editor The editor instance as passed by TinyMCE. - */ - onSetup( editor ) { - this.editor = editor; - } - setFocusedElement() { if ( this.props.setFocusedElement ) { this.props.setFocusedElement( this.props.instanceId ); @@ -837,12 +827,10 @@ export class RichText extends Component {
- { isSelected && this.editor && this.multilineTag === 'li' && ( + { isSelected && this.multilineTag === 'li' && ( this.onChange( this.createRecord() ) } value={ record } onChange={ this.onChange } /> @@ -867,7 +855,6 @@ export class RichText extends Component { ( @@ -82,26 +109,24 @@ export const ListEdit = ( { onTagNameChange && { icon: 'editor-ul', title: __( 'Convert to unordered list' ), - isActive: isActiveListType( editor, 'ul', tagName ), + isActive: isActiveListType( 'ul', tagName ), onClick() { - if ( isListRootSelected( editor ) ) { + onChange( changeListType( value, { type: 'ul' } ) ); + + if ( isListRootSelected() ) { onTagNameChange( 'ul' ); - } else { - editor.execCommand( 'InsertUnorderedList' ); - onSyncDOM(); } }, }, onTagNameChange && { icon: 'editor-ol', title: __( 'Convert to ordered list' ), - isActive: isActiveListType( editor, 'ol', tagName ), + isActive: isActiveListType( 'ol', tagName ), onClick() { - if ( isListRootSelected( editor ) ) { + onChange( changeListType( value, { type: 'ol' } ) ); + + if ( isListRootSelected() ) { onTagNameChange( 'ol' ); - } else { - editor.execCommand( 'InsertOrderedList' ); - onSyncDOM(); } }, }, diff --git a/packages/editor/src/components/rich-text/tinymce.js b/packages/editor/src/components/rich-text/tinymce.js index a29117bdce24d8..529fa15c1a54ce 100644 --- a/packages/editor/src/components/rich-text/tinymce.js +++ b/packages/editor/src/components/rich-text/tinymce.js @@ -200,16 +200,11 @@ export default class TinyMCE extends Component { lists_indent_on_tab: false, }; - if ( multilineTag === 'li' ) { - settings.plugins.push( 'lists' ); - } - tinymce.init( { ...settings, target: this.editorNode, setup: ( editor ) => { this.editor = editor; - this.props.onSetup( editor ); // TinyMCE resets the element content on initialization, even // when it's already identical to what exists currently. This diff --git a/packages/rich-text/src/change-list-type.js b/packages/rich-text/src/change-list-type.js new file mode 100644 index 00000000000000..fd1dede3c617ce --- /dev/null +++ b/packages/rich-text/src/change-list-type.js @@ -0,0 +1,53 @@ +/** + * Internal dependencies + */ + +import { LINE_SEPARATOR } from './special-characters'; +import { normaliseFormats } from './normalise-formats'; + +function getLineIndex( { start, text }, startIndex = start ) { + let index = startIndex; + + while ( index-- ) { + if ( text[ index ] === LINE_SEPARATOR ) { + return index; + } + } +} + +export function changeListType( value, newFormat ) { + const { text, formats, start, end } = value; + const startLineIndex = getLineIndex( value, start ); + const endLineIndex = getLineIndex( value, end ); + const startLineFormats = formats[ startLineIndex ] || []; + const endLineFormats = formats[ endLineIndex ] || []; + const length = text.length; + const newFormats = formats.slice( 0 ); + const startCount = startLineFormats.length - 1; + const endCount = endLineFormats.length - 1; + + for ( let index = startLineIndex || 0; index < length; index++ ) { + if ( text[ index ] !== LINE_SEPARATOR ) { + continue; + } + + if ( ( newFormats[ index ] || [] ).length <= startCount ) { + break; + } + + if ( ! newFormats[ index ] ) { + continue; + } + + newFormats[ index ] = newFormats[ index ].map( ( format, i ) => { + return i < startCount || i > endCount ? format : newFormat; + } ); + } + + return normaliseFormats( { + text, + formats: newFormats, + start, + end, + } ); +} diff --git a/packages/rich-text/src/index.js b/packages/rich-text/src/index.js index 712c1a609b3441..86f7cd1b29ae1d 100644 --- a/packages/rich-text/src/index.js +++ b/packages/rich-text/src/index.js @@ -27,3 +27,4 @@ export { LINE_SEPARATOR } from './special-characters'; export { unregisterFormatType } from './unregister-format-type'; export { indentListItems } from './indent-list-items'; export { outdentListItems } from './outdent-list-items'; +export { changeListType } from './change-list-type'; From 699e6d5da9a8dde21e59fd932fa2196464ebc8bb Mon Sep 17 00:00:00 2001 From: iseulde Date: Fri, 11 Jan 2019 13:12:03 +0100 Subject: [PATCH 09/15] Add tests --- packages/rich-text/src/change-list-type.js | 26 +++++- .../rich-text/src/test/change-list-type.js | 71 +++++++++++++++ ...ent-line-items.js => indent-list-items.js} | 2 +- .../rich-text/src/test/outdent-list-items.js | 90 +++++++++++++++++++ 4 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 packages/rich-text/src/test/change-list-type.js rename packages/rich-text/src/test/{indent-line-items.js => indent-list-items.js} (98%) create mode 100644 packages/rich-text/src/test/outdent-list-items.js diff --git a/packages/rich-text/src/change-list-type.js b/packages/rich-text/src/change-list-type.js index fd1dede3c617ce..5a2bf01dd9b7c6 100644 --- a/packages/rich-text/src/change-list-type.js +++ b/packages/rich-text/src/change-list-type.js @@ -15,18 +15,37 @@ function getLineIndex( { start, text }, startIndex = start ) { } } +function getParentLineIndex( { text, formats }, startIndex, formatCount ) { + let index = startIndex; + + while ( index-- ) { + if ( text[ index ] !== LINE_SEPARATOR ) { + continue; + } + + const formatsAtIndex = formats[ index ] || []; + + if ( formatsAtIndex.length === formatCount - 1 ) { + return index; + } + } +} + export function changeListType( value, newFormat ) { const { text, formats, start, end } = value; const startLineIndex = getLineIndex( value, start ); const endLineIndex = getLineIndex( value, end ); const startLineFormats = formats[ startLineIndex ] || []; const endLineFormats = formats[ endLineIndex ] || []; + const startIndex = getParentLineIndex( value, startLineIndex, startLineFormats.length ); const length = text.length; const newFormats = formats.slice( 0 ); const startCount = startLineFormats.length - 1; const endCount = endLineFormats.length - 1; - for ( let index = startLineIndex || 0; index < length; index++ ) { + let changed; + + for ( let index = startIndex + 1 || 0; index < length; index++ ) { if ( text[ index ] !== LINE_SEPARATOR ) { continue; } @@ -39,11 +58,16 @@ export function changeListType( value, newFormat ) { continue; } + changed = true; newFormats[ index ] = newFormats[ index ].map( ( format, i ) => { return i < startCount || i > endCount ? format : newFormat; } ); } + if ( ! changed ) { + return value; + } + return normaliseFormats( { text, formats: newFormats, diff --git a/packages/rich-text/src/test/change-list-type.js b/packages/rich-text/src/test/change-list-type.js new file mode 100644 index 00000000000000..992d9a74fc949d --- /dev/null +++ b/packages/rich-text/src/test/change-list-type.js @@ -0,0 +1,71 @@ +/** + * External dependencies + */ +import deepFreeze from 'deep-freeze'; + +/** + * Internal dependencies + */ + +import { changeListType } from '../change-list-type'; +import { getSparseArrayLength } from './helpers'; +import { LINE_SEPARATOR } from '../special-characters'; + +describe( 'changeListType', () => { + const ul = { type: 'ul' }; + const ol = { type: 'ol' }; + + it( 'should only change list type if list item is indented', () => { + const record = { + formats: [ , ], + text: '1', + start: 1, + end: 1, + }; + const result = changeListType( deepFreeze( record ), ul ); + + expect( result ).toEqual( record ); + expect( result ).toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 0 ); + } ); + + it( 'should change list type', () => { + const record = { + formats: [ , [ ul ] ], + text: `1${ LINE_SEPARATOR }`, + start: 2, + end: 2, + }; + const expected = { + formats: [ , [ ol ] ], + text: `1${ LINE_SEPARATOR }`, + start: 2, + end: 2, + }; + const result = changeListType( deepFreeze( record ), ol ); + + expect( result ).toEqual( expected ); + expect( result ).not.toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 1 ); + } ); + + it( 'should outdent with multiple lines selected', () => { + const record = { + formats: [ , [ ul ], , [ ul ], , [ ul, ul ], , [ ul ], , [ ul ], , , , [ ul ], , ], + text: `a${ LINE_SEPARATOR }1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }i${ LINE_SEPARATOR }3${ LINE_SEPARATOR }4${ LINE_SEPARATOR }b`, + start: 4, + end: 9, + }; + const expected = { + formats: [ , [ ol ], , [ ol ], , [ ol, ul ], , [ ol ], , [ ol ], , , , [ ul ], , ], + text: `a${ LINE_SEPARATOR }1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }i${ LINE_SEPARATOR }3${ LINE_SEPARATOR }4${ LINE_SEPARATOR }b`, + start: 4, + end: 9, + }; + const result = changeListType( deepFreeze( record ), ol ); + + expect( result ).toEqual( expected ); + expect( result ).not.toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 6 ); + } ); +} ); diff --git a/packages/rich-text/src/test/indent-line-items.js b/packages/rich-text/src/test/indent-list-items.js similarity index 98% rename from packages/rich-text/src/test/indent-line-items.js rename to packages/rich-text/src/test/indent-list-items.js index e789f578fbb07a..445635118ee02e 100644 --- a/packages/rich-text/src/test/indent-line-items.js +++ b/packages/rich-text/src/test/indent-list-items.js @@ -11,7 +11,7 @@ import { indentListItems } from '../indent-list-items'; import { getSparseArrayLength } from './helpers'; import { LINE_SEPARATOR } from '../special-characters'; -describe( 'applyFormat', () => { +describe( 'indentListItems', () => { const ul = { type: 'ul' }; const ol = { type: 'ol' }; diff --git a/packages/rich-text/src/test/outdent-list-items.js b/packages/rich-text/src/test/outdent-list-items.js new file mode 100644 index 00000000000000..35d39f0481c145 --- /dev/null +++ b/packages/rich-text/src/test/outdent-list-items.js @@ -0,0 +1,90 @@ +/** + * External dependencies + */ +import deepFreeze from 'deep-freeze'; + +/** + * Internal dependencies + */ + +import { outdentListItems } from '../outdent-list-items'; +import { getSparseArrayLength } from './helpers'; +import { LINE_SEPARATOR } from '../special-characters'; + +describe( 'outdentListItems', () => { + const ul = { type: 'ul' }; + + it( 'should not outdent only item', () => { + const record = { + formats: [ , ], + text: '1', + start: 1, + end: 1, + }; + const result = outdentListItems( deepFreeze( record ), ul ); + + expect( result ).toEqual( record ); + expect( result ).toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 0 ); + } ); + + it( 'should indent', () => { + const record = { + formats: [ , [ ul ] ], + text: `1${ LINE_SEPARATOR }`, + start: 2, + end: 2, + }; + const expected = { + formats: [ , , ], + text: `1${ LINE_SEPARATOR }`, + start: 2, + end: 2, + }; + const result = outdentListItems( deepFreeze( record ), ul ); + + expect( result ).toEqual( expected ); + expect( result ).not.toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 0 ); + } ); + + it( 'should outdent two levels deep', () => { + const record = { + formats: [ , [ ul ], , [ ul, ul ], , ], + text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + start: 5, + end: 5, + }; + const expected = { + formats: [ , [ ul ], , [ ul ], , ], + text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + start: 5, + end: 5, + }; + const result = outdentListItems( deepFreeze( record ), ul ); + + expect( result ).toEqual( expected ); + expect( result ).not.toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 2 ); + } ); + + it( 'should outdent with multiple lines selected', () => { + const record = { + formats: [ , [ ul ], , [ ul, ul ], , ], + text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + start: 2, + end: 5, + }; + const expected = { + formats: [ , , , [ ul ], , ], + text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + start: 2, + end: 5, + }; + const result = outdentListItems( deepFreeze( record ), ul ); + + expect( result ).toEqual( expected ); + expect( result ).not.toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 1 ); + } ); +} ); From b84f0b9d5d008dd2050844a4f263bf55106b7c87 Mon Sep 17 00:00:00 2001 From: iseulde Date: Tue, 15 Jan 2019 18:02:22 +0000 Subject: [PATCH 10/15] Add e2e tests --- .../blocks/__snapshots__/list.test.js.snap | 42 +++++++++++++ packages/e2e-tests/specs/blocks/list.test.js | 59 +++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/packages/e2e-tests/specs/blocks/__snapshots__/list.test.js.snap b/packages/e2e-tests/specs/blocks/__snapshots__/list.test.js.snap index 19a5186156809e..a4cb6cdb75be57 100644 --- a/packages/e2e-tests/specs/blocks/__snapshots__/list.test.js.snap +++ b/packages/e2e-tests/specs/blocks/__snapshots__/list.test.js.snap @@ -86,6 +86,18 @@ exports[`List should be immeadiately saved on indentation 1`] = ` " `; +exports[`List should change the base list type 1`] = ` +" +
+" +`; + +exports[`List should change the indented list type 1`] = ` +" +
  • a
    1. 1
+" +`; + exports[`List should create paragraph on split at end and merge back with content 1`] = ` "
  • one
@@ -102,6 +114,36 @@ exports[`List should create paragraph on split at end and merge back with conten " `; +exports[`List should indent and outdent level 1 1`] = ` +" +
  • a
    • 1
+" +`; + +exports[`List should indent and outdent level 1 2`] = ` +" +
  • a
  • 1
+" +`; + +exports[`List should indent and outdent level 2 1`] = ` +" +
  • a
    • 1
      • i
+" +`; + +exports[`List should indent and outdent level 2 2`] = ` +" +
  • a
    • 1
    • i
+" +`; + +exports[`List should indent and outdent level 2 3`] = ` +" +
  • a
    • 1
  • i
+" +`; + exports[`List should split indented list item 1`] = ` "
  • one
    • two
    • three
diff --git a/packages/e2e-tests/specs/blocks/list.test.js b/packages/e2e-tests/specs/blocks/list.test.js index 1401698c43a110..022c0b88b13362 100644 --- a/packages/e2e-tests/specs/blocks/list.test.js +++ b/packages/e2e-tests/specs/blocks/list.test.js @@ -203,4 +203,63 @@ describe( 'List', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); + + it( 'should change the base list type', async () => { + await insertBlock( 'List' ); + await page.click( 'button[aria-label="Convert to ordered list"]' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'should change the indented list type', async () => { + await insertBlock( 'List' ); + await page.keyboard.type( 'a' ); + await page.keyboard.press( 'Enter' ); + await pressKeyWithModifier( 'primary', 'm' ); + await page.keyboard.type( '1' ); + + // Pointer device is needed. Shift+Tab won't focus the toolbar. + // To do: fix so Shift+Tab works. + await page.mouse.move( 200, 300, { steps: 10 } ); + await page.mouse.move( 250, 350, { steps: 10 } ); + + await page.click( 'button[aria-label="Convert to ordered list"]' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'should indent and outdent level 1', async () => { + await insertBlock( 'List' ); + await page.keyboard.type( 'a' ); + await page.keyboard.press( 'Enter' ); + await pressKeyWithModifier( 'primary', 'm' ); + await page.keyboard.type( '1' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + + await pressKeyWithModifier( 'primaryShift', 'm' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'should indent and outdent level 2', async () => { + await insertBlock( 'List' ); + await page.keyboard.type( 'a' ); + await page.keyboard.press( 'Enter' ); + await pressKeyWithModifier( 'primary', 'm' ); + await page.keyboard.type( '1' ); + await page.keyboard.press( 'Enter' ); + await pressKeyWithModifier( 'primary', 'm' ); + await page.keyboard.type( 'i' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + + await pressKeyWithModifier( 'primaryShift', 'm' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + + await pressKeyWithModifier( 'primaryShift', 'm' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); } ); From b94e41d1d13f7039d0a6ceb0174279cd15b9073d Mon Sep 17 00:00:00 2001 From: iseulde Date: Thu, 24 Jan 2019 20:00:45 +0100 Subject: [PATCH 11/15] Add some basic docs. Clean up. --- packages/rich-text/src/change-list-type.js | 40 ++++------ packages/rich-text/src/get-line-index.js | 26 ++++++ .../rich-text/src/get-parent-line-index.js | 33 ++++++++ packages/rich-text/src/indent-list-items.js | 80 ++++++++++--------- packages/rich-text/src/outdent-list-items.js | 46 ++++------- 5 files changed, 129 insertions(+), 96 deletions(-) create mode 100644 packages/rich-text/src/get-line-index.js create mode 100644 packages/rich-text/src/get-parent-line-index.js diff --git a/packages/rich-text/src/change-list-type.js b/packages/rich-text/src/change-list-type.js index 5a2bf01dd9b7c6..92a244df84479a 100644 --- a/packages/rich-text/src/change-list-type.js +++ b/packages/rich-text/src/change-list-type.js @@ -4,33 +4,21 @@ import { LINE_SEPARATOR } from './special-characters'; import { normaliseFormats } from './normalise-formats'; +import { getLineIndex } from './get-line-index'; +import { getParentLineIndex } from './get-parent-line-index'; -function getLineIndex( { start, text }, startIndex = start ) { - let index = startIndex; - - while ( index-- ) { - if ( text[ index ] === LINE_SEPARATOR ) { - return index; - } - } -} - -function getParentLineIndex( { text, formats }, startIndex, formatCount ) { - let index = startIndex; - - while ( index-- ) { - if ( text[ index ] !== LINE_SEPARATOR ) { - continue; - } - - const formatsAtIndex = formats[ index ] || []; - - if ( formatsAtIndex.length === formatCount - 1 ) { - return index; - } - } -} - +/** + * Changes the list type of the selected indented list, if any. Looks at the + * currently selected list item and takes the parent list, then changes the list + * type of this list. When multiple lines are selected, the parent lists are + * takes and changed. + * + * @param {Object} value Value to change. + * @param {Object} newFormat The new list format object. Choose between + * `{ type: 'ol' }` and `{ type: 'ul' }`. + * + * @return {Object} The changed value. + */ export function changeListType( value, newFormat ) { const { text, formats, start, end } = value; const startLineIndex = getLineIndex( value, start ); diff --git a/packages/rich-text/src/get-line-index.js b/packages/rich-text/src/get-line-index.js new file mode 100644 index 00000000000000..ff44efb98fceba --- /dev/null +++ b/packages/rich-text/src/get-line-index.js @@ -0,0 +1,26 @@ +/** + * Internal dependencies + */ + +import { LINE_SEPARATOR } from './special-characters'; + +/** + * Gets the currently selected line index, or the first line index if the + * selection spans over multiple items. + * + * @param {Object} value Value to get the line index from. + * @param {boolean} startIndex Optional index that should be contained by the + * line. Defaults to the selection start of the + * value. + * + * @return {?boolean} The line index. Undefined if not found. + */ +export function getLineIndex( { start, text }, startIndex = start ) { + let index = startIndex; + + while ( index-- ) { + if ( text[ index ] === LINE_SEPARATOR ) { + return index; + } + } +} diff --git a/packages/rich-text/src/get-parent-line-index.js b/packages/rich-text/src/get-parent-line-index.js new file mode 100644 index 00000000000000..d01303f7f6e2d5 --- /dev/null +++ b/packages/rich-text/src/get-parent-line-index.js @@ -0,0 +1,33 @@ +/** + * Internal dependencies + */ + +import { LINE_SEPARATOR } from './special-characters'; + +/** + * Gets the index of the first parent list. To get the parent list formats, we + * go through every list item until we find one with exactly one format type + * less. + * + * @param {Object} value Value to search. + * @param {number} startIndex Index to start search at. + * + * @return {Array} The parent list line index. + */ +export function getParentLineIndex( { text, formats }, startIndex ) { + const startFormats = formats[ startIndex ] || []; + + let index = startIndex; + + while ( index-- ) { + if ( text[ index ] !== LINE_SEPARATOR ) { + continue; + } + + const formatsAtIndex = formats[ index ] || []; + + if ( formatsAtIndex.length === startFormats - 1 ) { + return index; + } + } +} diff --git a/packages/rich-text/src/indent-list-items.js b/packages/rich-text/src/indent-list-items.js index 8d736d84ff1d1f..0759ed8f32294f 100644 --- a/packages/rich-text/src/indent-list-items.js +++ b/packages/rich-text/src/indent-list-items.js @@ -4,46 +4,20 @@ import { LINE_SEPARATOR } from './special-characters'; import { normaliseFormats } from './normalise-formats'; +import { getLineIndex } from './get-line-index'; -function getLineIndex( { start, text }, startIndex = start ) { - let index = startIndex; - - while ( index-- ) { - if ( text[ index ] === LINE_SEPARATOR ) { - return index; - } - } -} - -function getTargetFormats( - { text, formats }, - startIndex, - formatCount, -) { - let index = startIndex; - - while ( index-- ) { - if ( text[ index ] !== LINE_SEPARATOR ) { - continue; - } - - if ( ! formats[ index ] ) { - return []; - } - - if ( formats[ index ].length === formatCount + 1 ) { - return formats[ index ]; - } else if ( formats[ index ].length === formatCount ) { - return formats[ index ]; - } - } - - return []; -} - +/** + * Indents any selected list items if possible. + * + * @param {Object} value Value to change. + * @param {Object} rootFormat + * + * @return {Object} The changed value. + */ export function indentListItems( value, rootFormat ) { const lineIndex = getLineIndex( value ); + // There is only one line, so the line cannot be indented. if ( lineIndex === undefined ) { return value; } @@ -53,19 +27,49 @@ export function indentListItems( value, rootFormat ) { const previousLineIndex = getLineIndex( value, lineIndex ); const formatsAtPreviousLineIndex = formats[ previousLineIndex ] || []; + // The the indentation of the current line is greater than previous line, + // then the line cannot be furter indented. if ( formatsAtLineIndex.length > formatsAtPreviousLineIndex.length ) { return value; } const newFormats = formats.slice(); - const targetFormatCount = formatsAtLineIndex.length; - const targetFormats = getTargetFormats( value, lineIndex, targetFormatCount ); + const targetFormats = formats[ getLineIndex( value, lineIndex ) ] || []; for ( let index = lineIndex; index < end; index++ ) { if ( text[ index ] !== LINE_SEPARATOR ) { continue; } + // If the indentation of the previous line is the same as the current + // line, then duplicate the type and append all current types. E.g. + // + // 1. one + // 2. two <= Selected + // * three <= Selected + // + // should become: + // + // 1. one + // 1. two <= Selected + // * three <= Selected + // + // ^ Inserted list + // + // Otherwise take the target formats and append traling lists. E.g. + // + // 1. one + // * target + // 2. two <= Selected + // * three <= Selected + // + // should become: + // + // 1. one + // * target + // * two <= Selected + // * three <= Selected + // if ( targetFormats.length === formatsAtLineIndex.length ) { const lastformat = targetFormats[ targetFormats.length - 1 ] || rootFormat; diff --git a/packages/rich-text/src/outdent-list-items.js b/packages/rich-text/src/outdent-list-items.js index e41b48c7d4fcf1..78036aae165e1b 100644 --- a/packages/rich-text/src/outdent-list-items.js +++ b/packages/rich-text/src/outdent-list-items.js @@ -4,35 +4,16 @@ import { LINE_SEPARATOR } from './special-characters'; import { normaliseFormats } from './normalise-formats'; +import { getLineIndex } from './get-line-index'; +import { getParentLineIndex } from './get-parent-line-index'; -function getLineIndex( { start, text }, startIndex = start ) { - let index = startIndex; - - while ( index-- ) { - if ( text[ index ] === LINE_SEPARATOR ) { - return index; - } - } -} - -function getParentFormats( { text, formats }, startIndex, formatCount ) { - let index = startIndex; - - while ( index-- ) { - if ( text[ index ] !== LINE_SEPARATOR ) { - continue; - } - - const formatsAtIndex = formats[ index ] || []; - - if ( formatsAtIndex.length === formatCount - 1 ) { - return formatsAtIndex; - } - } - - return []; -} - +/** + * Outdents any selected list items if possible. + * + * @param {Object} value Value to change. + * + * @return {Object} The changed value. + */ export function outdentListItems( value ) { const { text, formats, start, end } = value; const lineIndex = getLineIndex( value ); @@ -43,16 +24,17 @@ export function outdentListItems( value ) { } const newFormats = formats.slice( 0 ); - const parentFormats = getParentFormats( value, lineIndex, lineFormats.length ); + const parentFormats = formats[ getParentLineIndex( value, lineIndex ) ] || []; for ( let index = lineIndex; index < end; index++ ) { if ( text[ index ] !== LINE_SEPARATOR ) { continue; } - const trailingFormats = newFormats[ index ].slice( parentFormats.length + 1 ); - - newFormats[ index ] = parentFormats.concat( trailingFormats ); + // Omit the indentation level where the selection starts. + newFormats[ index ] = parentFormats.concat( + newFormats[ index ].slice( parentFormats.length + 1 ) + ); if ( newFormats[ index ].length === 0 ) { delete newFormats[ lineIndex ]; From 0ab1e63192cbe55f0036420de55a96a485717e9d Mon Sep 17 00:00:00 2001 From: iseulde Date: Thu, 24 Jan 2019 20:03:58 +0100 Subject: [PATCH 12/15] Remove duplicate wp-tinymce dependency --- lib/packages-dependencies.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/packages-dependencies.php b/lib/packages-dependencies.php index 6d170f25f56152..60a125997f3bcf 100644 --- a/lib/packages-dependencies.php +++ b/lib/packages-dependencies.php @@ -133,7 +133,6 @@ ), 'wp-editor' => array( 'lodash', - 'wp-tinymce', 'wp-a11y', 'wp-api-fetch', 'wp-blob', From 6c77f19c4d74022b284b64ca531d314baf8e9186 Mon Sep 17 00:00:00 2001 From: iseulde Date: Fri, 25 Jan 2019 09:01:51 +0100 Subject: [PATCH 13/15] Clean up --- .../src/components/rich-text/list-edit.js | 43 ++++++++----------- packages/rich-text/src/change-list-type.js | 11 ++--- .../rich-text/src/get-parent-line-index.js | 10 +++-- packages/rich-text/src/indent-list-items.js | 6 +-- 4 files changed, 32 insertions(+), 38 deletions(-) diff --git a/packages/editor/src/components/rich-text/list-edit.js b/packages/editor/src/components/rich-text/list-edit.js index e4ea42b23854ca..4aa1b2556857a9 100644 --- a/packages/editor/src/components/rich-text/list-edit.js +++ b/packages/editor/src/components/rich-text/list-edit.js @@ -18,11 +18,17 @@ import { import { RichTextShortcut } from './shortcut'; import BlockFormatControls from '../block-format-controls'; -function isListRootSelected() { +/** + * Gets the selected list node, which is the closest list node to the start of + * the selection. + * + * @return {?Element} The selected list node, or undefined if none is selected. + */ +function getSelectedListNode() { const selection = window.getSelection(); if ( selection.rangeCount === 0 ) { - return true; + return; } let { startContainer } = selection.getRangeAt( 0 ); @@ -34,38 +40,27 @@ function isListRootSelected() { const rootNode = startContainer.closest( '*[contenteditable]' ); if ( ! rootNode || ! rootNode.contains( startContainer ) ) { - return true; + return; } - return startContainer.closest( 'ol,ul' ) === rootNode; + return startContainer.closest( 'ol,ul' ); } -function isActiveListType( tagName, rootTagName ) { - const selection = window.getSelection(); - - if ( selection.rangeCount === 0 ) { - return tagName === rootTagName; - } - - let { startContainer } = selection.getRangeAt( 0 ); +function isListRootSelected() { + const listNode = getSelectedListNode(); - if ( startContainer.nodeType === window.Node.TEXT_NODE ) { - startContainer = startContainer.parentNode; - } + // Consider the root list selected if nothing is selected. + return ! listNode || listNode.contentEditable === 'true'; +} - const rootNode = startContainer.closest( '*[contenteditable]' ); +function isActiveListType( tagName, rootTagName ) { + const listNode = getSelectedListNode(); - if ( ! rootNode || ! rootNode.contains( startContainer ) ) { + if ( ! listNode ) { return tagName === rootTagName; } - const list = startContainer.closest( 'ol,ul' ); - - if ( ! list ) { - return; - } - - return list.nodeName.toLowerCase() === tagName; + return listNode.nodeName.toLowerCase() === tagName; } export const ListEdit = ( { diff --git a/packages/rich-text/src/change-list-type.js b/packages/rich-text/src/change-list-type.js index 92a244df84479a..2b92dda0ab92ce 100644 --- a/packages/rich-text/src/change-list-type.js +++ b/packages/rich-text/src/change-list-type.js @@ -21,19 +21,16 @@ import { getParentLineIndex } from './get-parent-line-index'; */ export function changeListType( value, newFormat ) { const { text, formats, start, end } = value; - const startLineIndex = getLineIndex( value, start ); - const endLineIndex = getLineIndex( value, end ); - const startLineFormats = formats[ startLineIndex ] || []; - const endLineFormats = formats[ endLineIndex ] || []; - const startIndex = getParentLineIndex( value, startLineIndex, startLineFormats.length ); - const length = text.length; + const startLineFormats = formats[ getLineIndex( value, start ) ] || []; + const endLineFormats = formats[ getLineIndex( value, end ) ] || []; + const startIndex = getParentLineIndex( value, start ); const newFormats = formats.slice( 0 ); const startCount = startLineFormats.length - 1; const endCount = endLineFormats.length - 1; let changed; - for ( let index = startIndex + 1 || 0; index < length; index++ ) { + for ( let index = startIndex + 1 || 0; index < text.length; index++ ) { if ( text[ index ] !== LINE_SEPARATOR ) { continue; } diff --git a/packages/rich-text/src/get-parent-line-index.js b/packages/rich-text/src/get-parent-line-index.js index d01303f7f6e2d5..332764dc45bd30 100644 --- a/packages/rich-text/src/get-parent-line-index.js +++ b/packages/rich-text/src/get-parent-line-index.js @@ -15,9 +15,8 @@ import { LINE_SEPARATOR } from './special-characters'; * @return {Array} The parent list line index. */ export function getParentLineIndex( { text, formats }, startIndex ) { - const startFormats = formats[ startIndex ] || []; - let index = startIndex; + let startFormats; while ( index-- ) { if ( text[ index ] !== LINE_SEPARATOR ) { @@ -26,7 +25,12 @@ export function getParentLineIndex( { text, formats }, startIndex ) { const formatsAtIndex = formats[ index ] || []; - if ( formatsAtIndex.length === startFormats - 1 ) { + if ( ! startFormats ) { + startFormats = formatsAtIndex; + continue; + } + + 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 0759ed8f32294f..39226de4722dc4 100644 --- a/packages/rich-text/src/indent-list-items.js +++ b/packages/rich-text/src/indent-list-items.js @@ -24,17 +24,15 @@ export function indentListItems( value, rootFormat ) { const { text, formats, start, end } = value; const formatsAtLineIndex = formats[ lineIndex ] || []; - const previousLineIndex = getLineIndex( value, lineIndex ); - const formatsAtPreviousLineIndex = formats[ previousLineIndex ] || []; + const targetFormats = formats[ getLineIndex( value, lineIndex ) ] || []; // The the indentation of the current line is greater than previous line, // then the line cannot be furter indented. - if ( formatsAtLineIndex.length > formatsAtPreviousLineIndex.length ) { + if ( formatsAtLineIndex.length > targetFormats.length ) { return value; } const newFormats = formats.slice(); - const targetFormats = formats[ getLineIndex( value, lineIndex ) ] || []; for ( let index = lineIndex; index < end; index++ ) { if ( text[ index ] !== LINE_SEPARATOR ) { From a205d8fadc46532e6463d39f8ae602d42b7df5b6 Mon Sep 17 00:00:00 2001 From: iseulde Date: Fri, 25 Jan 2019 09:45:31 +0100 Subject: [PATCH 14/15] Add more docs, fix getSelectedListNode --- .../src/components/rich-text/list-edit.js | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/editor/src/components/rich-text/list-edit.js b/packages/editor/src/components/rich-text/list-edit.js index 4aa1b2556857a9..81de868f627192 100644 --- a/packages/editor/src/components/rich-text/list-edit.js +++ b/packages/editor/src/components/rich-text/list-edit.js @@ -18,6 +18,8 @@ import { import { RichTextShortcut } from './shortcut'; import BlockFormatControls from '../block-format-controls'; +const { TEXT_NODE, ELEMENT_NODE } = window.Node; + /** * Gets the selected list node, which is the closest list node to the start of * the selection. @@ -33,10 +35,14 @@ function getSelectedListNode() { let { startContainer } = selection.getRangeAt( 0 ); - if ( startContainer.nodeType === window.Node.TEXT_NODE ) { + if ( startContainer.nodeType === TEXT_NODE ) { startContainer = startContainer.parentNode; } + if ( startContainer.nodeType !== ELEMENT_NODE ) { + return; + } + const rootNode = startContainer.closest( '*[contenteditable]' ); if ( ! rootNode || ! rootNode.contains( startContainer ) ) { @@ -46,6 +52,12 @@ function getSelectedListNode() { return startContainer.closest( 'ol,ul' ); } +/** + * Whether or not the root list is selected. + * + * @return {boolean} True if the root list or nothing is selected, false if an + * inner list is selected. + */ function isListRootSelected() { const listNode = getSelectedListNode(); @@ -53,6 +65,15 @@ function isListRootSelected() { return ! listNode || listNode.contentEditable === 'true'; } +/** + * Wether or not the selected list has the given tag name. + * + * @param {string} tagName The tag name the list should have. + * @param {string} rootTagName The current root tag name, to compare with in + * case nothing is selected. + * + * @return {boolean} [description] + */ function isActiveListType( tagName, rootTagName ) { const listNode = getSelectedListNode(); From e4dc45d1c63df0af965e27c0f7afaaa24cda8c68 Mon Sep 17 00:00:00 2001 From: iseulde Date: Mon, 28 Jan 2019 11:31:07 +0100 Subject: [PATCH 15/15] Put duplicate text values in constant --- .../rich-text/src/test/change-list-type.js | 7 ++++-- .../rich-text/src/test/indent-list-items.js | 24 ++++++++++++------- .../rich-text/src/test/outdent-list-items.js | 18 +++++++++----- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/packages/rich-text/src/test/change-list-type.js b/packages/rich-text/src/test/change-list-type.js index 992d9a74fc949d..3817c66ba7977e 100644 --- a/packages/rich-text/src/test/change-list-type.js +++ b/packages/rich-text/src/test/change-list-type.js @@ -50,15 +50,18 @@ describe( 'changeListType', () => { } ); it( 'should outdent with multiple lines selected', () => { + // As we're testing list formats, the text should remain the same. + 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 ], , ], - text: `a${ LINE_SEPARATOR }1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }i${ LINE_SEPARATOR }3${ LINE_SEPARATOR }4${ LINE_SEPARATOR }b`, + text, start: 4, end: 9, }; const expected = { formats: [ , [ ol ], , [ ol ], , [ ol, ul ], , [ ol ], , [ ol ], , , , [ ul ], , ], - text: `a${ LINE_SEPARATOR }1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }i${ LINE_SEPARATOR }3${ LINE_SEPARATOR }4${ LINE_SEPARATOR }b`, + text, start: 4, end: 9, }; diff --git a/packages/rich-text/src/test/indent-list-items.js b/packages/rich-text/src/test/indent-list-items.js index 445635118ee02e..c55d5063d21a8b 100644 --- a/packages/rich-text/src/test/indent-list-items.js +++ b/packages/rich-text/src/test/indent-list-items.js @@ -30,15 +30,17 @@ describe( 'indentListItems', () => { } ); it( 'should indent', () => { + // As we're testing list formats, the text should remain the same. + const text = `1${ LINE_SEPARATOR }`; const record = { formats: [ , , ], - text: `1${ LINE_SEPARATOR }`, + text, start: 2, end: 2, }; const expected = { formats: [ , [ ul ] ], - text: `1${ LINE_SEPARATOR }`, + text, start: 2, end: 2, }; @@ -64,15 +66,17 @@ describe( 'indentListItems', () => { } ); 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 ], , ], - text: `1${ LINE_SEPARATOR }${ LINE_SEPARATOR }`, + text, start: 3, end: 3, }; const expected = { formats: [ , [ ol ], [ ol ] ], - text: `1${ LINE_SEPARATOR }${ LINE_SEPARATOR }`, + text, start: 3, end: 3, }; @@ -84,15 +88,17 @@ describe( 'indentListItems', () => { } ); 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 ], , ], - text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + text, start: 5, end: 5, }; const expected = { formats: [ , [ ul ], , [ ul, ul ], , ], - text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + text, start: 5, end: 5, }; @@ -104,15 +110,17 @@ describe( 'indentListItems', () => { } ); 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 ], , ], - text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + text, start: 2, end: 5, }; const expected = { formats: [ , [ ul ], , [ ul, ul ], , ], - text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + text, start: 2, end: 5, }; diff --git a/packages/rich-text/src/test/outdent-list-items.js b/packages/rich-text/src/test/outdent-list-items.js index 35d39f0481c145..d321a4c02ffe83 100644 --- a/packages/rich-text/src/test/outdent-list-items.js +++ b/packages/rich-text/src/test/outdent-list-items.js @@ -29,15 +29,17 @@ describe( 'outdentListItems', () => { } ); it( 'should indent', () => { + // As we're testing list formats, the text should remain the same. + const text = `1${ LINE_SEPARATOR }`; const record = { formats: [ , [ ul ] ], - text: `1${ LINE_SEPARATOR }`, + text, start: 2, end: 2, }; const expected = { formats: [ , , ], - text: `1${ LINE_SEPARATOR }`, + text, start: 2, end: 2, }; @@ -49,15 +51,17 @@ describe( 'outdentListItems', () => { } ); 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 ], , ], - text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + text, start: 5, end: 5, }; const expected = { formats: [ , [ ul ], , [ ul ], , ], - text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + text, start: 5, end: 5, }; @@ -69,15 +73,17 @@ describe( 'outdentListItems', () => { } ); 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 ], , ], - text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + text, start: 2, end: 5, }; const expected = { formats: [ , , , [ ul ], , ], - text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`, + text, start: 2, end: 5, };