Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #27 from ckeditor/t/5
Browse files Browse the repository at this point in the history
Fix: The Autoformat should not require other features. Closes #5 #17.

NOTE: The Autoformat feature doesn't require Bold, Italic, Heading, etc. any longer. In order to make the most of the plugin, please make sure that relevant features are loaded in your editor.
  • Loading branch information
oleq committed May 18, 2017
2 parents 6bf4240 + e62d0ab commit d22c5b6
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 49 deletions.
9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
116 changes: 73 additions & 43 deletions src/autoformat.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
*/
Expand All @@ -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,
Expand All @@ -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 } );
} );
}
}
}
}
}
105 changes: 104 additions & 1 deletion tests/autoformat.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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;
Expand Down Expand Up @@ -141,4 +145,103 @@ describe( 'Autoformat', () => {
expect( getData( doc ) ).to.equal( '<paragraph>foo <$text bold="true">bar</$text>[] baz</paragraph>' );
} );
} );

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, '<paragraph>*[]</paragraph>' );
doc.enqueueChanges( () => {
batch.insert( doc.selection.getFirstPosition(), ' ' );
} );

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

it( 'should not replace minus character with bulleted list item', () => {
setData( doc, '<paragraph>-[]</paragraph>' );
doc.enqueueChanges( () => {
batch.insert( doc.selection.getFirstPosition(), ' ' );
} );

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

it( 'should not replace digit with numbered list item', () => {
setData( doc, '<paragraph>1.[]</paragraph>' );
doc.enqueueChanges( () => {
batch.insert( doc.selection.getFirstPosition(), ' ' );
} );

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

it( 'should not replace hash character with heading', () => {
setData( doc, '<paragraph>#[]</paragraph>' );
doc.enqueueChanges( () => {
batch.insert( doc.selection.getFirstPosition(), ' ' );
} );

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

it( 'should not replace two hash characters with heading level 2', () => {
setData( doc, '<paragraph>##[]</paragraph>' );
doc.enqueueChanges( () => {
batch.insert( doc.selection.getFirstPosition(), ' ' );
} );

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

it( 'should not replace both `**` with bold', () => {
setData( doc, '<paragraph>**foobar*[]</paragraph>' );
doc.enqueueChanges( () => {
batch.insert( doc.selection.getFirstPosition(), '*' );
} );

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

it( 'should not replace both `*` with italic', () => {
setData( doc, '<paragraph>*foobar[]</paragraph>' );
doc.enqueueChanges( () => {
batch.insert( doc.selection.getFirstPosition(), '*' );
} );

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

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, '<paragraph>##[]</paragraph>' );
doc.enqueueChanges( () => {
batch.insert( doc.selection.getFirstPosition(), ' ' );
} );

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

0 comments on commit d22c5b6

Please sign in to comment.