diff --git a/package.json b/package.json
index 4e64be2..be30d04 100644
--- a/package.json
+++ b/package.json
@@ -4,17 +4,16 @@
"description": "Replaces predefined characters with corresponding structures.",
"keywords": [],
"dependencies": {
- "@ckeditor/ckeditor5-basic-styles": "^0.8.1",
"@ckeditor/ckeditor5-core": "^0.8.1",
- "@ckeditor/ckeditor5-engine": "^0.10.0",
- "@ckeditor/ckeditor5-heading": "^0.9.1",
- "@ckeditor/ckeditor5-list": "^0.6.1"
+ "@ckeditor/ckeditor5-engine": "^0.10.0"
},
"devDependencies": {
+ "@ckeditor/ckeditor5-basic-styles": "^0.8.1",
"@ckeditor/ckeditor5-dev-lint": "^3.0.0",
"@ckeditor/ckeditor5-editor-classic": "^0.7.3",
"@ckeditor/ckeditor5-enter": "^0.9.1",
- "@ckeditor/ckeditor5-list": "*",
+ "@ckeditor/ckeditor5-heading": "^0.9.1",
+ "@ckeditor/ckeditor5-list": "^0.6.1",
"@ckeditor/ckeditor5-paragraph": "^0.8.0",
"@ckeditor/ckeditor5-typing": "^0.9.1",
"@ckeditor/ckeditor5-undo": "^0.8.1",
diff --git a/src/autoformat.js b/src/autoformat.js
index fa40cfb..3f6fd00 100644
--- a/src/autoformat.js
+++ b/src/autoformat.js
@@ -10,10 +10,6 @@
import BlockAutoformatEngine from './blockautoformatengine';
import InlineAutoformatEngine from './inlineautoformatengine';
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-import HeadingEngine from '@ckeditor/ckeditor5-heading/src/headingengine';
-import ListEngine from '@ckeditor/ckeditor5-list/src/listengine';
-import BoldEngine from '@ckeditor/ckeditor5-basic-styles/src/boldengine';
-import ItalicEngine from '@ckeditor/ckeditor5-basic-styles/src/italicengine';
/**
* Includes a set of predefined autoformatting actions.
@@ -47,16 +43,13 @@ import ItalicEngine from '@ckeditor/ckeditor5-basic-styles/src/italicengine';
* * `**foo bar**` or `__foo bar__` – will bold the text,
* * `*foo bar*` or `_foo bar_` – will italicize the text,
*
+ * NOTE: Remember to add proper features to the editor configuration. Autoformatting will be enabled only for those
+ * commands that are included in the actual configuration. For example: `bold` autoformatting will not work if there is no
+ * `bold` command registered in the editor.
+ *
* @extends module:core/plugin~Plugin
*/
export default class Autoformat extends Plugin {
- /**
- * @inheritDoc
- */
- static get requires() {
- return [ HeadingEngine, ListEngine, BoldEngine, ItalicEngine ];
- }
-
/**
* @inheritDoc
*/
@@ -67,44 +60,38 @@ export default class Autoformat extends Plugin {
/**
* @inheritDoc
*/
- init() {
+ afterInit() {
this._addListAutoformats();
+ this._addBasicStylesAutoformats();
this._addHeadingAutoformats();
- this._addInlineAutoformats();
}
/**
- * Adds autoformatting related to ListEngine commands.
+ * Adds autoformatting related to the {@link module:list/list~List}.
*
* When typed:
- * - `* ` or `- ` - paragraph will be changed to a bulleted list,
- * - `1. ` or `1) ` - paragraph will be changed to a numbered list (1 can be any digit or list of digits).
+ * - `* ` 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 list of digits).
*
* @private
*/
_addListAutoformats() {
- new BlockAutoformatEngine( this.editor, /^[*-]\s$/, 'bulletedList' ); // eslint-disable-line no-new
- new BlockAutoformatEngine( this.editor, /^\d+[.|)]?\s$/, 'numberedList' ); // eslint-disable-line no-new
- }
+ const commands = this.editor.commands;
- /**
- * Adds autoformatting related to HeadingEngine commands.
- * When typed `# ` or `## ` or `### ` paragraph will be changed to a corresponding heading level.
- *
- * @private
- */
- _addHeadingAutoformats() {
- // eslint-disable-next-line no-new
- new BlockAutoformatEngine( this.editor, /^(#{1,3})\s$/, context => {
- const { batch, match } = context;
- const headingLevel = match[ 1 ].length;
+ if ( commands.has( 'bulletedList' ) ) {
+ // eslint-disable-next-line no-new
+ new BlockAutoformatEngine( this.editor, /^[*-]\s$/, 'bulletedList' );
+ }
- this.editor.execute( `heading${ headingLevel }`, { batch } );
- } );
+ if ( commands.has( 'numberedList' ) ) {
+ // eslint-disable-next-line no-new
+ new BlockAutoformatEngine( this.editor, /^\d+[.|)]?\s$/, 'numberedList' );
+ }
}
/**
- * Adds inline autoformatting capabilities to the editor.
+ * Adds autoformatting related to the {@link module:basic-styles/bold~Bold} and
+ * {@link module:basic-styles/italic~Italic}.
*
* When typed:
* - `**foobar**`: `**` characters are removed, and `foobar` is set to bold,
@@ -114,15 +101,58 @@ export default class Autoformat extends Plugin {
*
* @private
*/
- _addInlineAutoformats() {
- /* eslint-disable no-new */
- new InlineAutoformatEngine( this.editor, /(\*\*)([^*]+)(\*\*)$/g, 'bold' );
- new InlineAutoformatEngine( this.editor, /(__)([^_]+)(__)$/g, 'bold' );
-
- // The italic autoformatter cannot be triggered by the bold markers, so we need to check the
- // text before the pattern (e.g. `(?:^|[^\*])`).
- new InlineAutoformatEngine( this.editor, /(?:^|[^*])(\*)([^*_]+)(\*)$/g, 'italic' );
- new InlineAutoformatEngine( this.editor, /(?:^|[^_])(_)([^_]+)(_)$/g, 'italic' );
- /* eslint-enable no-new */
+ _addBasicStylesAutoformats() {
+ const commands = this.editor.commands;
+
+ if ( commands.has( 'bold' ) ) {
+ /* eslint-disable no-new */
+ new InlineAutoformatEngine( this.editor, /(\*\*)([^*]+)(\*\*)$/g, 'bold' );
+ new InlineAutoformatEngine( this.editor, /(__)([^_]+)(__)$/g, 'bold' );
+ /* eslint-enable no-new */
+ }
+
+ if ( commands.has( 'italic' ) ) {
+ // The italic autoformatter cannot be triggered by the bold markers, so we need to check the
+ // text before the pattern (e.g. `(?:^|[^\*])`).
+
+ /* eslint-disable no-new */
+ new InlineAutoformatEngine( this.editor, /(?:^|[^*])(\*)([^*_]+)(\*)$/g, 'italic' );
+ new InlineAutoformatEngine( this.editor, /(?:^|[^_])(_)([^_]+)(_)$/g, 'italic' );
+ /* eslint-enable no-new */
+ }
+ }
+
+ /**
+ * Adds autoformatting related to {@link module:heading/heading~Heading}.
+ *
+ * It is using a number at the end of the command name to associate it with the proper trigger:
+ * * `heading1` will be executed when typing `#`,
+ * * `heading2` will be executed when typing `##`,
+ * * `heading3` will be executed when typing `###`.
+ *
+ * @private
+ */
+ _addHeadingAutoformats() {
+ const commands = this.editor.commands;
+ const options = this.editor.config.get( 'heading.options' );
+
+ if ( options ) {
+ for ( const option of options ) {
+ const commandName = option.modelElement;
+ let match;
+
+ if ( commands.has( commandName ) && ( match = commandName.match( /\d+$/ ) ) ) {
+ const level = match[ 0 ];
+ const regExp = new RegExp( `^(#{${ level }})\\s$` );
+
+ // eslint-disable-next-line no-new
+ new BlockAutoformatEngine( this.editor, regExp, context => {
+ const { batch } = context;
+
+ this.editor.execute( commandName, { batch } );
+ } );
+ }
+ }
+ }
}
}
diff --git a/tests/autoformat.js b/tests/autoformat.js
index 705bc57..63dcf44 100644
--- a/tests/autoformat.js
+++ b/tests/autoformat.js
@@ -5,6 +5,10 @@
import Autoformat from '../src/autoformat';
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
+import ListEngine from '@ckeditor/ckeditor5-list/src/listengine';
+import HeadingEngine from '@ckeditor/ckeditor5-heading/src/headingengine';
+import BoldEngine from '@ckeditor/ckeditor5-basic-styles/src/boldengine';
+import ItalicEngine from '@ckeditor/ckeditor5-basic-styles/src/italicengine';
import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
import Enter from '@ckeditor/ckeditor5-enter/src/enter';
import { setData, getData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
@@ -17,7 +21,7 @@ describe( 'Autoformat', () => {
beforeEach( () => {
return VirtualTestEditor.create( {
- plugins: [ Enter, Paragraph, Autoformat ]
+ plugins: [ Enter, Paragraph, Autoformat, ListEngine, HeadingEngine, BoldEngine, ItalicEngine ]
} )
.then( newEditor => {
editor = newEditor;
@@ -141,4 +145,103 @@ describe( 'Autoformat', () => {
expect( getData( doc ) ).to.equal( 'foo <$text bold="true">bar$text>[] baz' );
} );
} );
+
+ describe( 'without commands', () => {
+ beforeEach( () => {
+ return VirtualTestEditor.create( {
+ plugins: [ Enter, Paragraph, Autoformat ]
+ } )
+ .then( newEditor => {
+ editor = newEditor;
+ doc = editor.document;
+ batch = doc.batch();
+ } );
+ } );
+
+ it( 'should not replace asterisk with bulleted list item', () => {
+ setData( doc, '*[]' );
+ doc.enqueueChanges( () => {
+ batch.insert( doc.selection.getFirstPosition(), ' ' );
+ } );
+
+ expect( getData( doc ) ).to.equal( '* []' );
+ } );
+
+ it( 'should not replace minus character with bulleted list item', () => {
+ setData( doc, '-[]' );
+ doc.enqueueChanges( () => {
+ batch.insert( doc.selection.getFirstPosition(), ' ' );
+ } );
+
+ expect( getData( doc ) ).to.equal( '- []' );
+ } );
+
+ it( 'should not replace digit with numbered list item', () => {
+ setData( doc, '1.[]' );
+ doc.enqueueChanges( () => {
+ batch.insert( doc.selection.getFirstPosition(), ' ' );
+ } );
+
+ expect( getData( doc ) ).to.equal( '1. []' );
+ } );
+
+ it( 'should not replace hash character with heading', () => {
+ setData( doc, '#[]' );
+ doc.enqueueChanges( () => {
+ batch.insert( doc.selection.getFirstPosition(), ' ' );
+ } );
+
+ expect( getData( doc ) ).to.equal( '# []' );
+ } );
+
+ it( 'should not replace two hash characters with heading level 2', () => {
+ setData( doc, '##[]' );
+ doc.enqueueChanges( () => {
+ batch.insert( doc.selection.getFirstPosition(), ' ' );
+ } );
+
+ expect( getData( doc ) ).to.equal( '## []' );
+ } );
+
+ it( 'should not replace both `**` with bold', () => {
+ setData( doc, '**foobar*[]' );
+ doc.enqueueChanges( () => {
+ batch.insert( doc.selection.getFirstPosition(), '*' );
+ } );
+
+ expect( getData( doc ) ).to.equal( '**foobar**[]' );
+ } );
+
+ it( 'should not replace both `*` with italic', () => {
+ setData( doc, '*foobar[]' );
+ doc.enqueueChanges( () => {
+ batch.insert( doc.selection.getFirstPosition(), '*' );
+ } );
+
+ expect( getData( doc ) ).to.equal( '*foobar*[]' );
+ } );
+
+ it( 'should use only configured headings', () => {
+ return VirtualTestEditor.create( {
+ plugins: [ Enter, Paragraph, Autoformat, ListEngine, HeadingEngine ],
+ heading: {
+ options: [
+ { modelElement: 'paragraph' },
+ { modelElement: 'heading1', viewElement: 'h2' }
+ ]
+ }
+ } )
+ .then( editor => {
+ doc = editor.document;
+ batch = doc.batch();
+
+ setData( doc, '##[]' );
+ doc.enqueueChanges( () => {
+ batch.insert( doc.selection.getFirstPosition(), ' ' );
+ } );
+
+ expect( getData( doc ) ).to.equal( '## []' );
+ } );
+ } );
+ } );
} );