Przeglądaj źródła

Merge branch 'master' into t/4

# Conflicts:
#	package.json
Maciej Gołaszewski 6 lat temu
rodzic
commit
3b14615e3d

+ 22 - 0
packages/ckeditor5-mention/CHANGELOG.md

@@ -1,6 +1,28 @@
 Changelog
 Changelog
 =========
 =========
 
 
+## [12.0.1](https://github.com/ckeditor/ckeditor5-mention/compare/v12.0.0...v12.0.1) (2019-07-10)
+
+Internal changes only (updated dependencies, documentation, etc.).
+
+
+## [12.0.0](https://github.com/ckeditor/ckeditor5-mention/compare/v11.0.0...v12.0.0) (2019-07-04)
+
+### Bug fixes
+
+* It should be possible to type before a mention which is at the beginning of a block. Closes [#77](https://github.com/ckeditor/ckeditor5-mention/issues/77). ([946e762](https://github.com/ckeditor/ckeditor5-mention/commit/946e762))
+* Mentions should work when different UTF character classes are used in the feed configuration. Closes [#38](https://github.com/ckeditor/ckeditor5-mention/issues/38). ([764f099](https://github.com/ckeditor/ckeditor5-mention/commit/764f099))
+* Partial mentions should not be downcasted (e.g. not copied to clipboard). Closes [#24](https://github.com/ckeditor/ckeditor5-mention/issues/24). ([8956b1f](https://github.com/ckeditor/ckeditor5-mention/commit/8956b1f))
+
+### Other changes
+
+* Moved the `TextWatcher` util to `@ckeditor/ckeditor5-typing`. ([a644043](https://github.com/ckeditor/ckeditor5-mention/commit/a644043))
+
+### BREAKING CHANGES
+
+* The `TextWatcher` util was moved to `@ckeditor/ckeditor5-typing`.
+
+
 ## [11.0.0](https://github.com/ckeditor/ckeditor5-mention/compare/v10.0.0...v11.0.0) (2019-06-05)
 ## [11.0.0](https://github.com/ckeditor/ckeditor5-mention/compare/v10.0.0...v11.0.0) (2019-06-05)
 
 
 ### Bug fixes
 ### Bug fixes

+ 7 - 0
packages/ckeditor5-mention/docs/features/mentions.md

@@ -19,6 +19,13 @@ You can type the "@" character to invoke the mention autocomplete UI. The demo b
 	Check out the {@link examples/chat-with-mentions more advanced example} of the mention feature used in a chat application.
 	Check out the {@link examples/chat-with-mentions more advanced example} of the mention feature used in a chat application.
 </info-box>
 </info-box>
 
 
+## Related productivity features
+
+In addition to enabling mentions, you may want to check the following productivity features:
+
+* {@link features/text-transformation Automatic text transformation} &mdash; allows automatically turning snippets such as `(tm)` into `™` and `"foo"` into `“foo”`.
+* {@link features/autoformat Autoformatting} &mdash; allows quickly applying formatting to the content you are writing.
+
 ## Configuration
 ## Configuration
 
 
 The minimal configuration of the mention feature requires defining a {@link module:mention/mention~MentionFeed `feed`} and a {@link module:mention/mention~MentionFeed `marker`}. You can also define `minimumCharacters` after which the autocomplete panel will show up.
 The minimal configuration of the mention feature requires defining a {@link module:mention/mention~MentionFeed `feed`} and a {@link module:mention/mention~MentionFeed `marker`}. You can also define `minimumCharacters` after which the autocomplete panel will show up.

+ 17 - 18
packages/ckeditor5-mention/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@ckeditor/ckeditor5-mention",
   "name": "@ckeditor/ckeditor5-mention",
-  "version": "11.0.0",
+  "version": "12.0.1",
   "description": "Mention feature for CKEditor 5.",
   "description": "Mention feature for CKEditor 5.",
   "keywords": [
   "keywords": [
     "ckeditor",
     "ckeditor",
@@ -10,27 +10,26 @@
     "ckeditor5-plugin"
     "ckeditor5-plugin"
   ],
   ],
   "dependencies": {
   "dependencies": {
-    "@ckeditor/ckeditor5-core": "^12.1.1",
-    "@ckeditor/ckeditor5-typing": "^12.0.2",
-    "@ckeditor/ckeditor5-ui": "^13.0.0",
-    "@ckeditor/ckeditor5-utils": "^12.1.1",
+    "@ckeditor/ckeditor5-core": "^12.2.1",
+    "@ckeditor/ckeditor5-ui": "^13.0.2",
+    "@ckeditor/ckeditor5-typing": "^12.1.1",
+    "@ckeditor/ckeditor5-utils": "^13.0.1",
     "lodash-es": "^4.17.10"
     "lodash-es": "^4.17.10"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "@ckeditor/ckeditor5-basic-styles": "^11.1.1",
-    "@ckeditor/ckeditor5-block-quote": "^11.1.0",
-    "@ckeditor/ckeditor5-clipboard": "^11.0.2",
-    "@ckeditor/ckeditor5-editor-classic": "^12.1.1",
-    "@ckeditor/ckeditor5-engine": "^13.1.1",
-    "@ckeditor/ckeditor5-font": "^11.1.1",
-    "@ckeditor/ckeditor5-link": "^11.0.2",
-    "@ckeditor/ckeditor5-paragraph": "^11.0.2",
-    "@ckeditor/ckeditor5-table": "^13.0.0",
-    "@ckeditor/ckeditor5-typing": "^12.0.2",
-    "@ckeditor/ckeditor5-undo": "^11.0.2",
-    "@ckeditor/ckeditor5-widget": "^11.0.2",
+    "@ckeditor/ckeditor5-basic-styles": "^11.1.3",
+    "@ckeditor/ckeditor5-block-quote": "^11.1.2",
+    "@ckeditor/ckeditor5-clipboard": "^12.0.1",
+    "@ckeditor/ckeditor5-editor-classic": "^12.1.3",
+    "@ckeditor/ckeditor5-engine": "^13.2.1",
+    "@ckeditor/ckeditor5-font": "^11.2.1",
+    "@ckeditor/ckeditor5-link": "^11.1.1",
+    "@ckeditor/ckeditor5-paragraph": "^11.0.4",
+    "@ckeditor/ckeditor5-table": "^13.0.2",
+    "@ckeditor/ckeditor5-undo": "^11.0.4",
+    "@ckeditor/ckeditor5-widget": "^11.0.4",
     "eslint": "^5.5.0",
     "eslint": "^5.5.0",
-    "eslint-config-ckeditor5": "^1.0.11",
+    "eslint-config-ckeditor5": "^2.0.0",
     "husky": "^1.3.1",
     "husky": "^1.3.1",
     "lint-staged": "^7.0.0",
     "lint-staged": "^7.0.0",
     "lodash": "^4.17.11"
     "lodash": "^4.17.11"

+ 7 - 6
packages/ckeditor5-mention/src/featuredetection.js

@@ -15,21 +15,22 @@
  */
  */
 export default {
 export default {
 	/**
 	/**
-	 * Indicates whether the current browser supports ES2018 Unicode punctuation groups `\p{P}`.
+	 * Indicates whether the current browser supports ES2018 Unicode groups like `\p{P}` or `\p{L}`.
 	 *
 	 *
 	 * @type {Boolean}
 	 * @type {Boolean}
 	 */
 	 */
-	isPunctuationGroupSupported: ( function() {
-		let punctuationSupported = false;
-		// Feature detection for Unicode punctuation groups. It's added in ES2018. Currently Firefox and Edge does not support it.
+	isUnicodeGroupSupported: ( function() {
+		let isSupported = false;
+
+		// Feature detection for Unicode groups. Added in ES2018. Currently Firefox and Edge do not support it.
 		// See https://github.com/ckeditor/ckeditor5-mention/issues/44#issuecomment-487002174.
 		// See https://github.com/ckeditor/ckeditor5-mention/issues/44#issuecomment-487002174.
 
 
 		try {
 		try {
-			punctuationSupported = '.'.search( new RegExp( '[\\p{P}]', 'u' ) ) === 0;
+			isSupported = 'ć'.search( new RegExp( '[\\p{L}]', 'u' ) ) === 0;
 		} catch ( error ) {
 		} catch ( error ) {
 			// Firefox throws a SyntaxError when the group is unsupported.
 			// Firefox throws a SyntaxError when the group is unsupported.
 		}
 		}
 
 
-		return punctuationSupported;
+		return isSupported;
 	}() )
 	}() )
 };
 };

+ 8 - 2
packages/ckeditor5-mention/src/mentioncommand.js

@@ -98,7 +98,10 @@ export default class MentionCommand extends Command {
 			 *
 			 *
 			 * @error mentioncommand-incorrect-marker
 			 * @error mentioncommand-incorrect-marker
 			 */
 			 */
-			throw new CKEditorError( 'mentioncommand-incorrect-marker: The marker must be a single character.' );
+			throw new CKEditorError(
+				'mentioncommand-incorrect-marker: The marker must be a single character.',
+				this
+			);
 		}
 		}
 
 
 		if ( mentionID.charAt( 0 ) != options.marker ) {
 		if ( mentionID.charAt( 0 ) != options.marker ) {
@@ -127,7 +130,10 @@ export default class MentionCommand extends Command {
 			 *
 			 *
 			 * @error mentioncommand-incorrect-id
 			 * @error mentioncommand-incorrect-id
 			 */
 			 */
-			throw new CKEditorError( 'mentioncommand-incorrect-id: The item id must start with the marker character.' );
+			throw new CKEditorError(
+				'mentioncommand-incorrect-id: The item id must start with the marker character.',
+				this
+			);
 		}
 		}
 
 
 		model.change( writer => {
 		model.change( writer => {

+ 15 - 5
packages/ckeditor5-mention/src/mentionediting.js

@@ -149,7 +149,8 @@ function createViewMentionElement( mention, viewWriter ) {
 	return viewWriter.createAttributeElement( 'span', attributes, options );
 	return viewWriter.createAttributeElement( 'span', attributes, options );
 }
 }
 
 
-// Model post-fixer that disallows typing with selection when the selection is placed after the text node with the mention attribute.
+// Model post-fixer that disallows typing with selection when the selection is placed after the text node with the mention attribute or
+// before a text node with mention attribute.
 //
 //
 // @param {module:engine/model/writer~Writer} writer
 // @param {module:engine/model/writer~Writer} writer
 // @param {module:engine/model/document~Document} doc
 // @param {module:engine/model/document~Document} doc
@@ -158,15 +159,24 @@ function selectionMentionAttributePostFixer( writer, doc ) {
 	const selection = doc.selection;
 	const selection = doc.selection;
 	const focus = selection.focus;
 	const focus = selection.focus;
 
 
-	if ( selection.isCollapsed && selection.hasAttribute( 'mention' ) && isNodeBeforeAText( focus ) ) {
+	if ( selection.isCollapsed && selection.hasAttribute( 'mention' ) && shouldNotTypeWithMentionAt( focus ) ) {
 		writer.removeSelectionAttribute( 'mention' );
 		writer.removeSelectionAttribute( 'mention' );
 
 
 		return true;
 		return true;
 	}
 	}
+}
 
 
-	function isNodeBeforeAText( position ) {
-		return position.nodeBefore && position.nodeBefore.is( 'text' );
-	}
+// Helper function to detect if mention attribute should be removed from selection.
+// This check makes only sense if the selection has mention attribute.
+//
+// The mention attribute should be removed from a selection when selection focus is placed:
+// a) after a text node
+// b) the position is at parents start - the selection will set attributes from node after.
+function shouldNotTypeWithMentionAt( position ) {
+	const isAtStart = position.isAtStart;
+	const isAfterAMention = position.nodeBefore && position.nodeBefore.is( 'text' );
+
+	return isAfterAMention || isAtStart;
 }
 }
 
 
 // Model post-fixer that removes the mention attribute from the modified text node.
 // Model post-fixer that removes the mention attribute from the modified text node.

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

@@ -186,7 +186,10 @@ export default class MentionUI extends Plugin {
 				 *
 				 *
 				 * @error mentionconfig-incorrect-marker
 				 * @error mentionconfig-incorrect-marker
 				 */
 				 */
-				throw new CKEditorError( 'mentionconfig-incorrect-marker: The marker must be provided and it must be a single character.' );
+				throw new CKEditorError(
+					'mentionconfig-incorrect-marker: The marker must be provided and it must be a single character.',
+					null
+				);
 			}
 			}
 
 
 			const minimumCharacters = mentionDescription.minimumCharacters || 0;
 			const minimumCharacters = mentionDescription.minimumCharacters || 0;
@@ -592,19 +595,20 @@ function getBalloonPanelPositions( preferredPosition ) {
 // @returns {RegExp}
 // @returns {RegExp}
 export function createRegExp( marker, minimumCharacters ) {
 export function createRegExp( marker, minimumCharacters ) {
 	const numberOfCharacters = minimumCharacters == 0 ? '*' : `{${ minimumCharacters },}`;
 	const numberOfCharacters = minimumCharacters == 0 ? '*' : `{${ minimumCharacters },}`;
-	const patternBase = featureDetection.isPunctuationGroupSupported ? '\\p{Ps}\\p{Pi}"\'' : '\\(\\[{"\'';
 
 
-	return new RegExp( buildPattern( patternBase, marker, numberOfCharacters ), 'u' );
-}
+	const openAfterCharacters = featureDetection.isUnicodeGroupSupported ? '\\p{Ps}\\p{Pi}"\'' : '\\(\\[{"\'';
+	const mentionCharacters = featureDetection.isUnicodeGroupSupported ? '\\p{L}\\p{N}' : 'a-zA-ZÀ-ž0-9';
 
 
-// Helper to build a RegExp pattern string for the marker.
-//
-// @param {String} whitelistedCharacters
-// @param {String} marker
-// @param {Number} minimumCharacters
-// @returns {String}
-function buildPattern( whitelistedCharacters, marker, numberOfCharacters ) {
-	return `(^|[ ${ whitelistedCharacters }])([${ marker }])([_a-zA-Z0-9À-ž]${ numberOfCharacters }?)$`;
+	// The pattern consists of 3 groups:
+	// - 0 (non-capturing): Opening sequence - start of the line, space or an opening punctuation character like "(" or "\"",
+	// - 1: The marker character,
+	// - 2: Mention input (taking the minimal length into consideration to trigger the UI),
+	//
+	// The pattern matches up to the caret (end of string switch - $).
+	//               (0:      opening sequence       )(1:  marker   )(2:                typed mention                 )$
+	const pattern = `(?:^|[ ${ openAfterCharacters }])([${ marker }])([_${ mentionCharacters }]${ numberOfCharacters })$`;
+
+	return new RegExp( pattern, 'u' );
 }
 }
 
 
 // Creates a test callback for the marker to be used in the text watcher instance.
 // Creates a test callback for the marker to be used in the text watcher instance.
@@ -627,7 +631,7 @@ function getFeedText( marker, text ) {
 
 
 	const match = text.match( regExp );
 	const match = text.match( regExp );
 
 
-	return match[ 3 ];
+	return match[ 2 ];
 }
 }
 
 
 // The default feed callback.
 // The default feed callback.

+ 4 - 3
packages/ckeditor5-mention/tests/mentioncommand.js

@@ -7,7 +7,8 @@ import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltestedit
 import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 
 
 import MentionCommand from '../src/mentioncommand';
 import MentionCommand from '../src/mentioncommand';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 
 describe( 'MentionCommand', () => {
 describe( 'MentionCommand', () => {
 	let editor, command, model, doc, selection;
 	let editor, command, model, doc, selection;
@@ -145,7 +146,7 @@ describe( 'MentionCommand', () => {
 			];
 			];
 
 
 			for ( const options of testCases ) {
 			for ( const options of testCases ) {
-				expect( () => command.execute( options ) ).to.throw( CKEditorError, /mentioncommand-incorrect-marker/ );
+				expectToThrowCKEditorError( () => command.execute( options ), /mentioncommand-incorrect-marker/, editor );
 			}
 			}
 		} );
 		} );
 
 
@@ -159,7 +160,7 @@ describe( 'MentionCommand', () => {
 			];
 			];
 
 
 			for ( const options of testCases ) {
 			for ( const options of testCases ) {
-				expect( () => command.execute( options ) ).to.throw( CKEditorError, /mentioncommand-incorrect-id/ );
+				expectToThrowCKEditorError( () => command.execute( options ), /mentioncommand-incorrect-id/, editor );
 			}
 			}
 		} );
 		} );
 	} );
 	} );

+ 19 - 0
packages/ckeditor5-mention/tests/mentionediting.js

@@ -272,6 +272,25 @@ describe( 'MentionEditing', () => {
 
 
 			expect( editor.getData() ).to.equal( '<p>foo <span class="mention" data-mention="@John">@John</span> bar</p>' );
 			expect( editor.getData() ).to.equal( '<p>foo <span class="mention" data-mention="@John">@John</span> bar</p>' );
 		} );
 		} );
+
+		it( 'should not allow to type with mention attribute before mention', () => {
+			editor.setData( '<p><span class="mention" data-mention="@John">@John</span> bar</p>' );
+
+			const paragraph = doc.getRoot().getChild( 0 );
+
+			// Set selection before mention.
+			model.change( writer => {
+				writer.setSelection( paragraph, 0 );
+			} );
+
+			expect( Array.from( doc.selection.getAttributes() ) ).to.deep.equal( [] );
+
+			model.change( writer => {
+				writer.insertText( 'a', doc.selection.getAttributes(), writer.createPositionAt( paragraph, 0 ) );
+			} );
+
+			expect( editor.getData() ).to.equal( '<p>a<span class="mention" data-mention="@John">@John</span> bar</p>' );
+		} );
 	} );
 	} );
 
 
 	describe( 'removing partial mention post-fixer', () => {
 	describe( 'removing partial mention post-fixer', () => {

+ 45 - 15
packages/ckeditor5-mention/tests/mentionui.js

@@ -14,7 +14,6 @@ import global from '@ckeditor/ckeditor5-utils/src/dom/global';
 import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 import DomEventData from '@ckeditor/ckeditor5-engine/src/view/observer/domeventdata';
 import DomEventData from '@ckeditor/ckeditor5-engine/src/view/observer/domeventdata';
 import EventInfo from '@ckeditor/ckeditor5-utils/src/eventinfo';
 import EventInfo from '@ckeditor/ckeditor5-utils/src/eventinfo';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';
 import ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';
 import log from '@ckeditor/ckeditor5-utils/src/log';
 import log from '@ckeditor/ckeditor5-utils/src/log';
 import env from '@ckeditor/ckeditor5-utils/src/env';
 import env from '@ckeditor/ckeditor5-utils/src/env';
@@ -23,6 +22,7 @@ import MentionUI, { createRegExp } from '../src/mentionui';
 import featureDetection from '../src/featuredetection';
 import featureDetection from '../src/featuredetection';
 import MentionEditing from '../src/mentionediting';
 import MentionEditing from '../src/mentionediting';
 import MentionsView from '../src/ui/mentionsview';
 import MentionsView from '../src/ui/mentionsview';
+import { assertCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 
 describe( 'MentionUI', () => {
 describe( 'MentionUI', () => {
 	let editor, model, doc, editingView, mentionUI, editorElement, mentionsView, panelView;
 	let editor, model, doc, editingView, mentionUI, editorElement, mentionsView, panelView;
@@ -68,22 +68,19 @@ describe( 'MentionUI', () => {
 	describe( 'init()', () => {
 	describe( 'init()', () => {
 		it( 'should throw if marker was not provided for feed', () => {
 		it( 'should throw if marker was not provided for feed', () => {
 			return createClassicTestEditor( { feeds: [ { feed: [ 'a' ] } ] } ).catch( error => {
 			return createClassicTestEditor( { feeds: [ { feed: [ 'a' ] } ] } ).catch( error => {
-				expect( error ).to.be.instanceOf( CKEditorError );
-				expect( error.message ).to.match( /mentionconfig-incorrect-marker/ );
+				assertCKEditorError( error, /mentionconfig-incorrect-marker/, null );
 			} );
 			} );
 		} );
 		} );
 
 
 		it( 'should throw if marker is empty string', () => {
 		it( 'should throw if marker is empty string', () => {
 			return createClassicTestEditor( { feeds: [ { marker: '', feed: [ 'a' ] } ] } ).catch( error => {
 			return createClassicTestEditor( { feeds: [ { marker: '', feed: [ 'a' ] } ] } ).catch( error => {
-				expect( error ).to.be.instanceOf( CKEditorError );
-				expect( error.message ).to.match( /mentionconfig-incorrect-marker/ );
+				assertCKEditorError( error, /mentionconfig-incorrect-marker/, null );
 			} );
 			} );
 		} );
 		} );
 
 
 		it( 'should throw if marker is longer then 1 character', () => {
 		it( 'should throw if marker is longer then 1 character', () => {
 			return createClassicTestEditor( { feeds: [ { marker: '$$', feed: [ 'a' ] } ] } ).catch( error => {
 			return createClassicTestEditor( { feeds: [ { marker: '$$', feed: [ 'a' ] } ] } ).catch( error => {
-				expect( error ).to.be.instanceOf( CKEditorError );
-				expect( error.message ).to.match( /mentionconfig-incorrect-marker/ );
+				assertCKEditorError( error, /mentionconfig-incorrect-marker/, null );
 			} );
 			} );
 		} );
 		} );
 	} );
 	} );
@@ -453,10 +450,10 @@ describe( 'MentionUI', () => {
 			let regExpStub;
 			let regExpStub;
 
 
 			// Cache the original value to restore it after the tests.
 			// Cache the original value to restore it after the tests.
-			const originalPunctuationSupport = featureDetection.isPunctuationGroupSupported;
+			const originalGroupSupport = featureDetection.isUnicodeGroupSupported;
 
 
 			before( () => {
 			before( () => {
-				featureDetection.isPunctuationGroupSupported = false;
+				featureDetection.isUnicodeGroupSupported = false;
 			} );
 			} );
 
 
 			beforeEach( () => {
 			beforeEach( () => {
@@ -469,21 +466,21 @@ describe( 'MentionUI', () => {
 			} );
 			} );
 
 
 			after( () => {
 			after( () => {
-				featureDetection.isPunctuationGroupSupported = originalPunctuationSupport;
+				featureDetection.isUnicodeGroupSupported = originalGroupSupport;
 			} );
 			} );
 
 
 			it( 'returns a simplified RegExp for browsers not supporting Unicode punctuation groups', () => {
 			it( 'returns a simplified RegExp for browsers not supporting Unicode punctuation groups', () => {
-				featureDetection.isPunctuationGroupSupported = false;
+				featureDetection.isUnicodeGroupSupported = false;
 				createRegExp( '@', 2 );
 				createRegExp( '@', 2 );
 				sinon.assert.calledOnce( regExpStub );
 				sinon.assert.calledOnce( regExpStub );
-				sinon.assert.calledWithExactly( regExpStub, '(^|[ \\(\\[{"\'])([@])([_a-zA-Z0-9À-ž]{2,}?)$', 'u' );
+				sinon.assert.calledWithExactly( regExpStub, '(?:^|[ \\(\\[{"\'])([@])([_a-zA-ZÀ-ž0-9]{2,})$', 'u' );
 			} );
 			} );
 
 
 			it( 'returns a ES2018 RegExp for browsers supporting Unicode punctuation groups', () => {
 			it( 'returns a ES2018 RegExp for browsers supporting Unicode punctuation groups', () => {
-				featureDetection.isPunctuationGroupSupported = true;
+				featureDetection.isUnicodeGroupSupported = true;
 				createRegExp( '@', 2 );
 				createRegExp( '@', 2 );
 				sinon.assert.calledOnce( regExpStub );
 				sinon.assert.calledOnce( regExpStub );
-				sinon.assert.calledWithExactly( regExpStub, '(^|[ \\p{Ps}\\p{Pi}"\'])([@])([_a-zA-Z0-9À-ž]{2,}?)$', 'u' );
+				sinon.assert.calledWithExactly( regExpStub, '(?:^|[ \\p{Ps}\\p{Pi}"\'])([@])([_\\p{L}\\p{N}]{2,})$', 'u' );
 			} );
 			} );
 		} );
 		} );
 
 
@@ -568,7 +565,7 @@ describe( 'MentionUI', () => {
 				// Belongs to Pi (Punctuation, Initial quote) group:
 				// Belongs to Pi (Punctuation, Initial quote) group:
 				'«', '‹', '⸌', ' ⸂', '⸠'
 				'«', '‹', '⸌', ' ⸂', '⸠'
 			] ) {
 			] ) {
-				testOpeningPunctuationCharacter( character, !featureDetection.isPunctuationGroupSupported );
+				testOpeningPunctuationCharacter( character, !featureDetection.isUnicodeGroupSupported );
 			}
 			}
 
 
 			it( 'should not show panel for marker in the middle of other word', () => {
 			it( 'should not show panel for marker in the middle of other word', () => {
@@ -824,6 +821,39 @@ describe( 'MentionUI', () => {
 			} );
 			} );
 		} );
 		} );
 
 
+		describe( 'unicode', () => {
+			beforeEach( () => {
+				return createClassicTestEditor( {
+					feeds: [
+						{
+							// Always return 5 items
+							feed: [ '@תַפּוּחַ', '@אַגָס', '@apple', '@pear' ],
+							marker: '@'
+						}
+					]
+				} );
+			} );
+
+			it( 'should open panel for unicode character ב', function() {
+				if ( !featureDetection.isUnicodeGroupSupported ) {
+					this.skip();
+				}
+
+				setData( model, '<paragraph>foo []</paragraph>' );
+
+				model.change( writer => {
+					writer.insertText( '@ס', doc.selection.getFirstPosition() );
+				} );
+
+				return waitForDebounce()
+					.then( () => {
+						expect( panelView.isVisible, 'panel is visible' ).to.be.true;
+						expect( editor.model.markers.has( 'mention' ), 'marker is inserted' ).to.be.true;
+						expect( mentionsView.items ).to.have.length( 1 );
+					} );
+			} );
+		} );
+
 		describe( 'asynchronous list with custom trigger', () => {
 		describe( 'asynchronous list with custom trigger', () => {
 			let feedCallbackStub, feedCallbackTimeout, feedCallbackCallTimes;
 			let feedCallbackStub, feedCallbackTimeout, feedCallbackCallTimes;