Skip to content

Commit

Permalink
Merge pull request #8735 from ckeditor/i/7518-to-do-list-autoformat
Browse files Browse the repository at this point in the history
Feature (autoformat): Square brackets should convert the current line to a to-do list item. Closes #7518.
  • Loading branch information
Reinmar authored Dec 31, 2020
2 parents fe2d6ee + e8d0c8c commit 9b7e7c9
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 4 deletions.
5 changes: 5 additions & 0 deletions packages/ckeditor5-autoformat/src/autoformat.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export default class Autoformat extends Plugin {
* When typed:
* - `* ` or `- ` – A paragraph will be changed to a bulleted list.
* - `1. ` or `1) ` – A paragraph will be changed to a numbered list ("1" can be any digit or a list of digits).
* - `[] ` or `[ ] ` – A paragraph will be changed to a to-do list.
*
* @private
*/
Expand All @@ -57,6 +58,10 @@ export default class Autoformat extends Plugin {
if ( commands.get( 'numberedList' ) ) {
blockAutoformatEditing( this.editor, this, /^1[.|)]\s$/, 'numberedList' );
}

if ( commands.get( 'todoList' ) ) {
blockAutoformatEditing( this.editor, this, /^\[\s?\]\s$/, 'todoList' );
}
}

/**
Expand Down
7 changes: 7 additions & 0 deletions packages/ckeditor5-autoformat/src/blockautoformatediting.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ export default function blockAutoformatEditing( editor, plugin, pattern, callbac
return;
}

// Only lists should be formatted inside the lists.
if ( blockToFormat.is( 'element', 'listItem' ) &&
![ 'numberedList', 'bulletedList', 'todoList' ].includes( callbackOrCommand )
) {
return;
}

// In case a command is bound, do not re-execute it over an existing block style which would result with a style removal.
// Instead just drop processing so that autoformat trigger text is not lost. E.g. writing "# " in a level 1 heading.
if ( command && command.value === true ) {
Expand Down
127 changes: 127 additions & 0 deletions packages/ckeditor5-autoformat/tests/autoformat.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Autoformat from '../src/autoformat';

import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
import ListEditing from '@ckeditor/ckeditor5-list/src/listediting';
import TodoListEditing from '@ckeditor/ckeditor5-list/src/todolistediting';
import HeadingEditing from '@ckeditor/ckeditor5-heading/src/headingediting';
import BoldEditing from '@ckeditor/ckeditor5-basic-styles/src/bold/boldediting';
import StrikethroughEditing from '@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughediting';
Expand Down Expand Up @@ -37,6 +38,7 @@ describe( 'Autoformat', () => {
Paragraph,
Autoformat,
ListEditing,
TodoListEditing,
HeadingEditing,
BoldEditing,
ItalicEditing,
Expand Down Expand Up @@ -103,6 +105,15 @@ describe( 'Autoformat', () => {

expect( getData( model ) ).to.equal( '<paragraph>Foo<softBreak></softBreak>* []</paragraph>' );
} );

it( 'should be converted from a to-do list', () => {
setData( model, '<listItem listIndent="0" listType="todo">*[]</listItem>' );
model.change( writer => {
writer.insertText( ' ', doc.selection.getFirstPosition() );
} );

expect( getData( model ) ).to.equal( '<listItem listIndent="0" listType="bulleted">[]</listItem>' );
} );
} );

describe( 'Numbered list', () => {
Expand Down Expand Up @@ -186,6 +197,92 @@ describe( 'Autoformat', () => {

expect( getData( model ) ).to.equal( '<listItem listIndent="0" listType="numbered">[]</listItem>' );
} );

it( 'should be converted from a to-do list', () => {
setData( model, '<listItem listIndent="0" listType="todo">1.[]</listItem>' );
model.change( writer => {
writer.insertText( ' ', doc.selection.getFirstPosition() );
} );

expect( getData( model ) ).to.equal( '<listItem listIndent="0" listType="numbered">[]</listItem>' );
} );
} );

describe( 'To-do list', () => {
function insertSpace() {
model.change( writer => {
writer.insertText( ' ', doc.selection.getFirstPosition() );
} );
}
function insertBrackets( content = '' ) {
model.change( writer => {
writer.insertText( '[' + content + ']', doc.selection.getFirstPosition() );
} );
}

it( 'should replace empty square brackets', () => {
setData( model, '[]' );
insertBrackets();
insertSpace();

expect( getData( model ) ).to.equal( '<listItem listIndent="0" listType="todo">[]</listItem>' );
} );

it( 'should replace square brackets with space inside', () => {
setData( model, '[]' );
insertBrackets( ' ' );
insertSpace();

expect( getData( model ) ).to.equal( '<listItem listIndent="0" listType="todo">[]</listItem>' );
} );

it( 'should be converted from a paragraph', () => {
setData( model, '<paragraph>[]Sample text</paragraph>' );
insertBrackets();
insertSpace();

expect( getData( model ) ).to.equal( '<listItem listIndent="0" listType="todo">[]Sample text</listItem>' );
} );

it( 'should be converted from a header', () => {
setData( model, '<heading1>[]Header text</heading1>' );
insertBrackets( ' ' );
insertSpace();

expect( getData( model ) ).to.equal( '<listItem listIndent="0" listType="todo">[]Header text</listItem>' );
} );

it( 'should be converted from a numbered list', () => {
setData( model, '<listItem listIndent="0" listType="numbered">[]Sample text</listItem>' );
insertBrackets();
insertSpace();

expect( getData( model ) ).to.equal( '<listItem listIndent="0" listType="todo">[]Sample text</listItem>' );
} );

it( 'should not replace the brackets if is not at the beginning of the line', () => {
setData( model, '<paragraph>Sample text []</paragraph>' );
insertBrackets( ' ' );
insertSpace();

expect( getData( model ) ).to.equal( '<paragraph>Sample text [ ] []</paragraph>' );
} );

it( 'should not replace the brackets if it contains a text', () => {
setData( model, '[]' );
insertBrackets( 'Foo' );
insertSpace();

expect( getData( model ) ).to.equal( '<paragraph>[Foo] []</paragraph>' );
} );

it( 'should not replace the brackets after <softBreak>', () => {
setData( model, '<paragraph>Foo<softBreak></softBreak>[]</paragraph>' );
insertBrackets();
insertSpace();

expect( getData( model ) ).to.equal( '<paragraph>Foo<softBreak></softBreak>[] []</paragraph>' );
} );
} );

describe( 'Heading', () => {
Expand Down Expand Up @@ -336,6 +433,15 @@ describe( 'Autoformat', () => {
expect( getData( model ) ).to.equal( '<listItem listIndent="0" listType="bulleted">1. > []</listItem>' );
} );

it( 'should not replace greater-than character when inside to-do list', () => {
setData( model, '<listItem listIndent="0" listType="todo">>[]</listItem>' );
model.change( writer => {
writer.insertText( ' ', doc.selection.getFirstPosition() );
} );

expect( getData( model ) ).to.equal( '<listItem listIndent="0" listType="todo">> []</listItem>' );
} );

it( 'should not replace greater-than character after <softBreak>', () => {
setData( model, '<paragraph>Foo<softBreak></softBreak>>[]</paragraph>' );
model.change( writer => {
Expand Down Expand Up @@ -400,6 +506,15 @@ describe( 'Autoformat', () => {

expect( getData( model ) ).to.equal( '<listItem listIndent="0" listType="bulleted">1. ```[]</listItem>' );
} );

it( 'should not replace triple grave accents when inside todo list', () => {
setData( model, '<listItem listIndent="0" listType="todo">``[]</listItem>' );
model.change( writer => {
writer.insertText( '`', doc.selection.getFirstPosition() );
} );

expect( getData( model ) ).to.equal( '<listItem listIndent="0" listType="todo">```[]</listItem>' );
} );
} );

describe( 'Inline autoformat', () => {
Expand Down Expand Up @@ -705,6 +820,18 @@ describe( 'Autoformat', () => {
expect( getData( model ) ).to.equal( '<paragraph>1. []</paragraph>' );
} );

it( 'should not replace square brackets with to-do list item', () => {
setData( model, '<paragraph>[]</paragraph>' );
model.change( writer => {
writer.insertText( '[]', doc.selection.getFirstPosition() );
} );
model.change( writer => {
writer.insertText( ' ', doc.selection.getFirstPosition() );
} );

expect( getData( model ) ).to.equal( '<paragraph>[] []</paragraph>' );
} );

it( 'should not replace hash character with heading', () => {
setData( model, '<paragraph>#[]</paragraph>' );
model.change( writer => {
Expand Down
37 changes: 33 additions & 4 deletions packages/ckeditor5-autoformat/tests/manual/autoformat.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor'
import Autoformat from '../../src/autoformat';
import Enter from '@ckeditor/ckeditor5-enter/src/enter';
import List from '@ckeditor/ckeditor5-list/src/list';
import TodoList from '@ckeditor/ckeditor5-list/src/todolist';
import BlockQuote from '@ckeditor/ckeditor5-block-quote/src/blockquote';
import Typing from '@ckeditor/ckeditor5-typing/src/typing';
import Heading from '@ckeditor/ckeditor5-heading/src/heading';
Expand All @@ -23,10 +24,38 @@ import ShiftEnter from '@ckeditor/ckeditor5-enter/src/shiftenter';

ClassicEditor
.create( document.querySelector( '#editor' ), {
plugins: [ Enter, Typing, Paragraph, Undo, Bold, Italic, Code, Strikethrough, Heading, List, Autoformat, BlockQuote, CodeBlock,
ShiftEnter ],
toolbar: [ 'heading', '|', 'numberedList', 'bulletedList', 'blockQuote', 'codeBlock', 'bold', 'italic', 'code', 'strikethrough',
'undo', 'redo' ]
plugins: [
Enter,
Typing,
Paragraph,
Undo,
Bold,
Italic,
Code,
Strikethrough,
Heading,
List,
TodoList,
Autoformat,
BlockQuote,
CodeBlock,
ShiftEnter
],
toolbar: [
'heading',
'|',
'numberedList',
'bulletedList',
'todoList',
'blockQuote',
'codeBlock',
'bold',
'italic',
'code',
'strikethrough',
'undo',
'redo'
]
} )
.then( editor => {
window.editor = editor;
Expand Down

0 comments on commit 9b7e7c9

Please sign in to comment.