Skip to content

Commit

Permalink
fix list indentation
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix committed Jan 29, 2019
1 parent ccbf07e commit d0868d0
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 36 deletions.
79 changes: 43 additions & 36 deletions packages/rich-text/src/indent-list-items.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,36 @@ import { LINE_SEPARATOR } from './special-characters';
import { normaliseFormats } from './normalise-formats';
import { getLineIndex } from './get-line-index';

/**
* Gets the line index of the first previous list item with higher indentation.
*
* @param {Object} value Value to search.
* @param {number} lineIndex Line index of the list item to compare with.
*
* @return {boolean} The line index.
*/
function getTargetLevelLineIndex( { text, formats }, lineIndex ) {
const startFormats = formats[ lineIndex ] || [];

let index = lineIndex;

while ( index-- ) {
if ( text[ index ] !== LINE_SEPARATOR ) {
continue;
}

const formatsAtIndex = formats[ index ] || [];

// Return the first line index that is one level higher. If the level is
// lower or equal, there is no result.
if ( formatsAtIndex.length === startFormats.length + 1 ) {
return index;
} else if ( formatsAtIndex.length <= startFormats.length ) {
return;
}
}
}

/**
* Indents any selected list items if possible.
*
Expand All @@ -23,62 +53,39 @@ export function indentListItems( value, rootFormat ) {
}

const { text, formats, start, end } = value;
const previousLineIndex = getLineIndex( value, lineIndex );
const formatsAtLineIndex = formats[ lineIndex ] || [];
const targetFormats = formats[ 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 > targetFormats.length ) {
if ( formatsAtLineIndex.length > formatsAtPreviousLineIndex.length ) {
return value;
}

const newFormats = formats.slice();
const targetLevelLineIndex = getTargetLevelLineIndex( 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 ) {
// 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 ] || [];
newFormats[ index ] = targetFormats.concat(
( newFormats[ index ] || [] ).slice( targetFormats.length - 1 )
);
} else {
const targetFormats = formats[ previousLineIndex ] || [];
const lastformat = targetFormats[ targetFormats.length - 1 ] || rootFormat;

newFormats[ index ] = targetFormats.concat(
[ lastformat ],
( newFormats[ index ] || [] ).slice( targetFormats.length )
);
} else {
newFormats[ index ] = targetFormats.concat(
( newFormats[ index ] || [] ).slice( targetFormats.length - 1 )
);
}
}

Expand Down
22 changes: 22 additions & 0 deletions packages/rich-text/src/test/indent-list-items.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,26 @@ describe( 'indentListItems', () => {
expect( result ).not.toBe( record );
expect( getSparseArrayLength( result.formats ) ).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 ], , , , ],
text,
start: 6,
end: 6,
};
const expected = {
formats: [ , [ ul ], , [ ul, ul ], , [ ul ], , ],
text,
start: 6,
end: 6,
};
const result = indentListItems( deepFreeze( record ), ul );

expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
expect( getSparseArrayLength( result.formats ) ).toBe( 3 );
} );
} );

0 comments on commit d0868d0

Please sign in to comment.