Sfoglia il codice sorgente

Add minimumCharacters support.

Maciej Gołaszewski 6 anni fa
parent
commit
dfbf7f271a

+ 3 - 0
packages/ckeditor5-mention/src/mention.js

@@ -58,6 +58,9 @@ export default class Mention extends Plugin {
  * @property {String} [marker='@'] The character which triggers autocompletion for mention.
  * @property {Array.<module:mention/mention~MentionFeedItem>|Function} feed The auto complete feed items. Provide array for
  * static configuration or a function that returns a promise for asynchronous feeds.
+ * @property {Number} [minimumCharacters=0] Specifies after how many characters show the autocomplete panel.
+ * @property {Function} [itemRenderer] Function that renders {module:mention/mention~MentionFeedItem}
+ * to the autocomplete list to a DOM elemnt.
  */
 
 /**

+ 12 - 8
packages/ckeditor5-mention/src/mentionui.js

@@ -110,8 +110,9 @@ export default class MentionUI extends Plugin {
 			const feed = mentionDescription.feed;
 
 			const marker = mentionDescription.marker || '@';
+			const minimumCharacters = mentionDescription.minimumCharacters || 0;
 			const feedCallback = typeof feed == 'function' ? feed : createFeedCallback( feed );
-			const watcher = this._setupTextWatcherForFeed( marker );
+			const watcher = this._setupTextWatcherForFeed( marker, minimumCharacters );
 			const itemRenderer = mentionDescription.itemRenderer;
 
 			const definition = { watcher, marker, feedCallback, itemRenderer };
@@ -248,12 +249,13 @@ export default class MentionUI extends Plugin {
 	 *
 	 * @private
 	 * @param {String} marker
+	 * @param {Number} minimumCharacters
 	 * @returns {TextWatcher}
 	 */
-	_setupTextWatcherForFeed( marker ) {
+	_setupTextWatcherForFeed( marker, minimumCharacters ) {
 		const editor = this.editor;
 
-		const watcher = new TextWatcher( editor, createTestCallback( marker ), createTextMatcher( marker ) );
+		const watcher = new TextWatcher( editor, createTestCallback( marker, minimumCharacters ), createTextMatcher( marker ) );
 
 		watcher.on( 'matched', ( evt, data ) => {
 			const matched = data.matched;
@@ -426,9 +428,10 @@ function getBalloonPanelPositions() {
 // Creates a regex pattern for marker.
 //
 // @param {String} marker
+// @param {Number} minimumCharacters
 // @returns {String}
-function createPattern( marker ) {
-	const numberOfCharacters = '*';
+function createPattern( marker, minimumCharacters ) {
+	const numberOfCharacters = minimumCharacters == 0 ? '*' : `{${ minimumCharacters },}`;
 
 	return `(^| )(${ marker })([_a-zA-Z0-9À-ž]${ numberOfCharacters }?)$`;
 }
@@ -436,9 +439,10 @@ function createPattern( marker ) {
 // Creates a test callback for marker to be used in text watcher instance.
 //
 // @param {String} marker
+// @param {Number} minimumCharacters
 // @returns {Function}
-function createTestCallback( marker ) {
-	const regExp = new RegExp( createPattern( marker ) );
+function createTestCallback( marker, minimumCharacters ) {
+	const regExp = new RegExp( createPattern( marker, minimumCharacters ) );
 
 	return text => regExp.test( text );
 }
@@ -448,7 +452,7 @@ function createTestCallback( marker ) {
 // @param {String} marker
 // @returns {Function}
 function createTextMatcher( marker ) {
-	const regExp = new RegExp( createPattern( marker ) );
+	const regExp = new RegExp( createPattern( marker, 0 ) );
 
 	return text => {
 		const match = text.match( regExp );

+ 40 - 0
packages/ckeditor5-mention/tests/mentionui.js

@@ -176,6 +176,46 @@ describe( 'MentionUI', () => {
 	} );
 
 	describe( 'typing integration', () => {
+		it( 'should show panel for matched marker after typing minimum characters', () => {
+			return createClassicTestEditor( [ Object.assign( { minimumCharacters: 2 }, staticConfig[ 0 ] ) ] )
+				.then( () => {
+					setData( model, '<paragraph>foo []</paragraph>' );
+
+					model.change( writer => {
+						writer.insertText( '@', doc.selection.getFirstPosition() );
+					} );
+				} )
+				.then( () => {
+					model.change( writer => {
+						writer.insertText( 'B', doc.selection.getFirstPosition() );
+					} );
+				} )
+				.then( waitForDebounce )
+				.then( () => {
+					expect( panelView.isVisible ).to.be.false;
+				} )
+				.then( waitForDebounce )
+				.then( () => {
+					model.change( writer => {
+						writer.insertText( 'a', doc.selection.getFirstPosition() );
+					} );
+				} )
+				.then( waitForDebounce )
+				.then( () => {
+					expect( panelView.isVisible ).to.be.true;
+					expect( listView.items ).to.have.length( 1 );
+
+					model.change( writer => {
+						writer.insertText( 'r', doc.selection.getFirstPosition() );
+					} );
+				} )
+				.then( waitForDebounce )
+				.then( () => {
+					expect( panelView.isVisible ).to.be.true;
+					expect( listView.items ).to.have.length( 1 );
+				} );
+		} );
+
 		describe( 'static list with default trigger', () => {
 			beforeEach( () => {
 				return createClassicTestEditor( staticConfig );