| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- /**
- * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
- /**
- * @module autoformat/blockautoformatediting
- */
- import LiveRange from '@ckeditor/ckeditor5-engine/src/model/liverange';
- /**
- * The block autoformatting engine. It allows to format various block patterns. For example,
- * it can be configured to turn a paragraph starting with `*` and followed by a space into a list item.
- *
- * The autoformatting operation is integrated with the undo manager,
- * so the autoformatting step can be undone if the user's intention was not 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 BlockAutoformatEditing {
- /**
- * Creates a listener triggered on `change` event in the document.
- * Calls the callback when inserted text matches the regular expression or the command name
- * if provided instead of the callback.
- *
- * Examples of usage:
- *
- * To convert a paragraph to heading 1 when `- ` is typed, using just the command name:
- *
- * new BlockAutoformatEditing( editor, /^\- $/, 'heading1' );
- *
- * To convert a paragraph to heading 1 when `- ` is typed, using just the callback:
- *
- * new BlockAutoformatEditing( editor, /^\- $/, ( context ) => {
- * const { match } = context;
- * const headingLevel = match[ 1 ].length;
- *
- * editor.execute( 'heading', {
- * formatId: `heading${ headingLevel }`
- * } );
- * } );
- *
- * @param {module:core/editor/editor~Editor} editor The editor instance.
- * @param {RegExp} pattern The regular expression to execute on just inserted text.
- * @param {Function|String} callbackOrCommand The callback to execute or the command to run when the text is matched.
- * In case of providing the callback, it receives the following parameter:
- * * {Object} match RegExp.exec() result of matching the pattern to inserted text.
- */
- constructor( editor, pattern, callbackOrCommand ) {
- let callback;
- let command = null;
- if ( typeof callbackOrCommand == 'function' ) {
- callback = callbackOrCommand;
- } else {
- // We assume that the actual command name was provided.
- command = editor.commands.get( callbackOrCommand );
- callback = () => {
- editor.execute( callbackOrCommand );
- };
- }
- editor.model.document.on( 'change', ( evt, batch ) => {
- if ( command && !command.isEnabled ) {
- return;
- }
- if ( batch.type == 'transparent' ) {
- return;
- }
- const changes = Array.from( editor.model.document.differ.getChanges() );
- const entry = changes[ 0 ];
- // Typing is represented by only a single change.
- if ( changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1 ) {
- return;
- }
- const item = entry.position.textNode || entry.position.nodeAfter;
- if ( !item.parent.is( 'paragraph' ) ) {
- return;
- }
- const match = pattern.exec( item.data );
- if ( !match ) {
- return;
- }
- // Use enqueueChange to create new batch to separate typing batch from the auto-format changes.
- editor.model.enqueueChange( writer => {
- // Matched range.
- const start = writer.createPositionAt( item.parent, 0 );
- const end = writer.createPositionAt( item.parent, match[ 0 ].length );
- const range = new LiveRange( start, end );
- const wasChanged = callback( { match } );
- // Remove matched text.
- if ( wasChanged !== false ) {
- writer.remove( range );
- }
- range.detach();
- } );
- } );
- }
- }
|