Procházet zdrojové kódy

Add mention feed configuration validation for marker.

Maciej Gołaszewski před 6 roky
rodič
revize
83d2ad4847

+ 17 - 0
packages/ckeditor5-mention/src/mentionui.js

@@ -14,6 +14,7 @@ import BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpa
 import clickOutsideHandler from '@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler';
 import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
 import Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';
+import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 
 import TextWatcher from './textwatcher';
 
@@ -110,6 +111,22 @@ export default class MentionUI extends Plugin {
 			const feed = mentionDescription.feed;
 
 			const marker = mentionDescription.marker;
+
+			if ( !marker || marker.length != 1 ) {
+				/**
+				 * The marker must be a single character.
+				 *
+				 * Correct markers: `'@'`, `'#'`.
+				 *
+				 * Incorrect markers: `'$$'`, `'[@'`.
+				 *
+				 * See {@link module:mention/mention~MentionConfig}.
+				 *
+				 * @error mentionconfig-incorrect-marker
+				 */
+				throw new CKEditorError( 'mentionconfig-incorrect-marker: The marker must be provided and be a single character.' );
+			}
+
 			const minimumCharacters = mentionDescription.minimumCharacters || 0;
 			const feedCallback = typeof feed == 'function' ? feed : createFeedCallback( feed );
 			const watcher = this._setupTextWatcherForFeed( marker, minimumCharacters );

+ 60 - 1
packages/ckeditor5-mention/tests/mentionui.js

@@ -19,6 +19,7 @@ import EventInfo from '@ckeditor/ckeditor5-utils/src/eventinfo';
 import MentionUI from '../src/mentionui';
 import MentionEditing from '../src/mentionediting';
 import MentionsView from '../src/ui/mentionsview';
+import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 
 describe( 'MentionUI', () => {
 	let editor, model, doc, editingView, mentionUI, editorElement, mentionsView, panelView, listView;
@@ -43,7 +44,9 @@ describe( 'MentionUI', () => {
 		sinon.restore();
 		editorElement.remove();
 
-		return editor.destroy();
+		if ( editor ) {
+			return editor.destroy();
+		}
 	} );
 
 	it( 'should create a plugin instance', () => {
@@ -53,6 +56,29 @@ describe( 'MentionUI', () => {
 		} );
 	} );
 
+	describe( 'init()', () => {
+		it( 'should throw if marker was not provided for feed', () => {
+			return createClassicTestEditor( { feeds: [ { feed: [ 'a' ] } ] } ).catch( error => {
+				expect( error ).to.be.instanceOf( CKEditorError );
+				expect( error.message ).to.match( /mentionconfig-incorrect-marker/ );
+			} );
+		} );
+
+		it( 'should throw if marker is empty string', () => {
+			return createClassicTestEditor( { feeds: [ { marker: '', feed: [ 'a' ] } ] } ).catch( error => {
+				expect( error ).to.be.instanceOf( CKEditorError );
+				expect( error.message ).to.match( /mentionconfig-incorrect-marker/ );
+			} );
+		} );
+
+		it( 'should throw if marker is longer then 1 character', () => {
+			return createClassicTestEditor( { feeds: [ { marker: '$$', feed: [ 'a' ] } ] } ).catch( error => {
+				expect( error ).to.be.instanceOf( CKEditorError );
+				expect( error.message ).to.match( /mentionconfig-incorrect-marker/ );
+			} );
+		} );
+	} );
+
 	describe( 'pluginName', () => {
 		it( 'should return plugin by its name', () => {
 			return createClassicTestEditor().then( () => {
@@ -462,6 +488,39 @@ describe( 'MentionUI', () => {
 					} );
 			} );
 
+			it( 'should not show panel when selection is changing (non-collapsed)', () => {
+				setData( model, '<paragraph>foo []</paragraph>' );
+
+				model.change( writer => {
+					writer.insertText( '@', doc.selection.getFirstPosition() );
+				} );
+
+				return waitForDebounce()
+					.then( () => {
+						expect( panelView.isVisible ).to.be.true;
+						expect( editor.model.markers.has( 'mention' ) ).to.be.true;
+
+						model.change( () => {
+							model.modifySelection( doc.selection, { direction: 'backward', unit: 'character' } );
+						} );
+					} )
+					.then( waitForDebounce )
+					.then( () => {
+						expect( panelView.isVisible ).to.be.false;
+						expect( editor.model.markers.has( 'mention' ) ).to.be.false;
+					} )
+					.then( () => {
+						model.change( () => {
+							model.modifySelection( doc.selection, { direction: 'backward', unit: 'character' } );
+						} );
+					} )
+					.then( waitForDebounce )
+					.then( () => {
+						expect( panelView.isVisible ).to.be.false;
+						expect( editor.model.markers.has( 'mention' ) ).to.be.false;
+					} );
+			} );
+
 			it( 'should not show panel when selection is after existing mention', () => {
 				setData( model, '<paragraph>foo [@John] bar[]</paragraph>' );
 				model.change( writer => {