8
0
Pārlūkot izejas kodu

First working version.

Maksymilian Barnaś 9 gadi atpakaļ
vecāks
revīzija
0bc192377a

+ 22 - 12
packages/ckeditor5-autoformat/src/autoformat.js

@@ -6,32 +6,36 @@
 import AutoformatEngine from './autoformatengine.js';
 import HeadingEngine from '../heading/headingengine.js';
 import Feature from '../core/feature.js';
-
+/**
+ * The autoformat feature. Looks for predefined regular expressions and converts inserted text accordingly.
+ *
+ * @memberOf autoformat
+ * @extends core.Feature
+ */
 export default class Autoformat extends Feature {
 	/**
 	 * @inheritDoc
 	 */
 	static get requires() {
-		return [ AutoformatEngine, HeadingEngine ];
+		return [ HeadingEngine ];
 	}
 
+	/**
+	 * @inheritDoc
+	 */
 	init() {
 		const editor = this.editor;
 
-		// I've noticed the commands are set only when they are required.
-		// I guess this is expected behavior, but it makes things harder.
-		// For now I'll require needed commands explicitly.
-
 		if ( editor.commands.has( 'blockquote' ) ) {
-			new AutoformatEngine( /^> $/, 'blockquote' );
+			new AutoformatEngine( editor, /^> $/, 'blockquote' );
 		}
 
 		if ( editor.commands.has( 'bulletedList' ) ) {
-			new AutoformatEngine( /^[\*\-] $/, 'bulletedList' );
+			new AutoformatEngine( editor, /^[\*\-] $/, 'bulletedList' );
 		}
 
 		if ( editor.commands.has( 'numberedList' ) ) {
-			new AutoformatEngine( /^\d+[\.|)]? $/, 'numberedList' ); // "1 A", "1. A", "123 A"
+			new AutoformatEngine( editor, /^\d+[\.|)]? $/, 'numberedList' ); // "1 A", "1. A", "123 A"
 		}
 
 		if ( editor.commands.has( 'heading' ) ) {
@@ -41,13 +45,19 @@ export default class Autoformat extends Feature {
 			// <p>## ^</p> -> <heading2>^</heading2> (two steps: executing heading command + removing the text prefix)
 			//
 			// After ctrl+z: <p>## ^</p> (so undo two steps)
-			new AutoformatEngine( /^(#{1,3}) $/, ( batch, regexpMatch ) => {
+			new AutoformatEngine( editor, /^(#{1,3}) $/, ( batch, match ) => {
 				// TODO The heading command may be reconfigured in the future to support a different number
 				// of headings. That option must be exposed somehow, because we need to know here whether the replacement
 				// can be done or not.
-				const headingLevel = regexpMatch[ 1 ].length;
 
-				editor.execute( 'heading', { batch, format: `heading${ headingLevel }` } );
+				const headingLevel = match[ 1 ].length;
+
+				// This part needs slightly changed HeadingCommand.
+				// TODO Commit change to ckeditor5-heading
+				editor.execute( 'heading', {
+					batch: batch,
+					formatId: `heading${ headingLevel }`
+				} );
 			} ); // "# A", "## A"...
 		}
 	}

+ 36 - 41
packages/ckeditor5-autoformat/src/autoformatengine.js

@@ -3,53 +3,48 @@
  * For licensing, see LICENSE.md.
  */
 
-import Feature from '../core/feature.js';
-
-export default class AutoformatEngine extends Feature {
-	init () {
-		// const editor = this.editor;
-		// const data = editor.data;
-		// const editing = editor.editing;
-
-		/**
-		for ( let format of formats ) {
-			// Skip paragraph - it is defined in required Paragraph feature.
-			if ( format.id !== 'paragraph' ) {
-				// Schema.
-				editor.document.schema.registerItem( format.id, '$block' );
-
-				// Build converter from model to view for data and editing pipelines.
-				buildModelConverter().for( data.modelToView, editing.modelToView )
-					.fromElement( format.id )
-					.toElement( format.viewElement );
-
-				// Build converter from view to model for data pipeline.
-				buildViewConverter().for( data.viewToModel )
-					.fromElement( format.viewElement )
-					.toElement( format.id );
+import TreeWalker from '../engine/model/treewalker.js';
+import Position from '../engine/model/position.js';
+
+export default class AutoformatEngine {
+	/**
+	 * Creates listener triggered on `change` event in document. Calls callback when inserted text matches regular expression.
+	 *
+	 * @param {core.editor.Editor} editor Editor instance.
+	 * @param {Regex} regex Regular expression to exec on just inserted text.
+	 * @param {Function} callback Callback to execute when text is matched.
+	 */
+	constructor ( editor, regex, callback ) {
+		editor.document.on( 'change', ( event, type, changes, batch ) => {
+			if ( type != 'insert' ) {
+				return;
 			}
-		}
 
-		// Register the heading command.
-		const command = new HeadingCommand( editor, formats );
-		editor.commands.set( 'heading', command );
+			for ( let value of changes.range.getItems( { singleCharacters: true } ) ) {
+				const walker = new TreeWalker( {
+					direction: 'backward',
+					startPosition: Position.createAfter( value )
+				} );
 
-		// If the enter command is added to the editor, alter its behavior.
-		// Enter at the end of a heading element should create a paragraph.
-		const enterCommand = editor.commands.get( 'enter' );
+				const currentValue = walker.next().value;
+				const text = currentValue.item.data;
 
-		if ( enterCommand ) {
-			this.listenTo( enterCommand, 'afterExecute', ( evt, data ) => {
-				const positionParent = editor.document.selection.getFirstPosition().parent;
-				const batch = data.batch;
-				const isHeading = formats.some( ( format ) => format.id == positionParent.name );
+				if ( !text ) {
+					return;
+				}
+
+				let result = regex.exec( text );
 
-				if ( isHeading && positionParent.name != command.defaultFormat.id && positionParent.childCount === 0 ) {
-					batch.rename( positionParent, command.defaultFormat.id );
+				if ( !result ) {
+					return;
 				}
-			} );
-		}
 
-		**/
+				const matched = result;
+
+				editor.document.enqueueChanges( () => {
+					callback( batch, matched  );
+				} );
+			}
+		} );
 	}
 }