| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
- /**
- * @module autoformat/blockautoformatengine
- */
- import Range from '@ckeditor/ckeditor5-engine/src/model/range';
- import TextProxy from '@ckeditor/ckeditor5-engine/src/model/textproxy';
- /**
- * The block autoformatting engine. Allows to format various block patterns. For example,
- * it can be configured to make a paragraph starting with "* " a list item.
- *
- * The autoformatting operation is integrated with the undo manager,
- * so the autoformatting step can be undone, if the user's intention wasn't to format the text.
- *
- * See the constructors documentation to learn how to create custom inline autoformatters. You can also use
- * the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters
- * (lists, headings, bold and italic).
- */
- export default class BlockAutoformatEngine {
- /**
- * Creates listener triggered on `change` event in document.
- * Calls callback when inserted text matches regular expression or command name
- * if provided instead of callback.
- *
- * Examples of usage:
- *
- * To convert paragraph to heading1 when `- ` is typed, using just commmand name:
- *
- * new BlockAutoformatEngine( editor, /^\- $/, 'heading1' );
- *
- * To convert paragraph to heading1 when `- ` is typed, using just callback:
- *
- * new BlockAutoformatEngine( editor, /^\- $/, ( context ) => {
- * const { batch, match } = context;
- * const headingLevel = match[ 1 ].length;
- *
- * editor.execute( 'heading', {
- * batch,
- * formatId: `heading${ headingLevel }`
- * } );
- * } );
- *
- * @param {module:core/editor/editor~Editor} editor Editor instance.
- * @param {RegExp} pattern Regular expression to exec on just inserted text.
- * @param {Function|String} callbackOrCommand Callback to execute or command to run when text is matched.
- * In case of providing callback it receives following parameters:
- * * {module:engine/model/batch~Batch} batch Newly created batch for autoformat changes.
- * * {Object} match RegExp.exec() result of matching pattern to inserted text.
- */
- constructor( editor, pattern, callbackOrCommand ) {
- let callback;
- if ( typeof callbackOrCommand == 'function' ) {
- callback = callbackOrCommand;
- } else {
- // We assume that the actual command name was provided.
- const command = callbackOrCommand;
- callback = ( context ) => {
- const { batch } = context;
- // Create new batch for removal and command execution.
- editor.execute( command, { batch } );
- };
- }
- editor.document.on( 'change', ( event, type, changes ) => {
- if ( type != 'insert' ) {
- return;
- }
- // Take the first element. Typing shouldn't add more than one element at once.
- // And if it is not typing (e.g. paste), Autoformat should not be fired.
- const value = changes.range.getItems().next().value;
- if ( !( value instanceof TextProxy ) ) {
- return;
- }
- const textNode = value.textNode;
- const text = textNode.data;
- // Run matching only on non-empty paragraphs.
- if ( textNode.parent.name !== 'paragraph' || !text ) {
- return;
- }
- const match = pattern.exec( text );
- if ( !match ) {
- return;
- }
- editor.document.enqueueChanges( () => {
- // Create new batch to separate typing batch from the Autoformat changes.
- const batch = editor.document.batch();
- // Matched range.
- const range = Range.createFromParentsAndOffsets( textNode.parent, 0, textNode.parent, match[ 0 ].length );
- // Remove matched text.
- batch.remove( range );
- callback( { batch, match } );
- } );
- } );
- }
- }
|