From 884630d399de5d0feaa698140aeac4204805b383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Mon, 20 May 2019 14:37:01 +0200 Subject: [PATCH 1/4] Fix mention ui integration with other contextual balloons. --- src/mentionui.js | 9 +++--- tests/mention-integration.js | 62 +++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/mentionui.js b/src/mentionui.js index 0a1ab9f..4787ee5 100644 --- a/src/mentionui.js +++ b/src/mentionui.js @@ -387,12 +387,13 @@ export default class MentionUI extends Plugin { * @private */ _hideUIAndRemoveMarker() { - if ( this.editor.model.markers.has( 'mention' ) ) { - this.editor.model.change( writer => writer.removeMarker( 'mention' ) ); + // Remove the mention view from balloon before removing marker - it is used by balloon position target(). + if ( this._balloon.hasView( this._mentionsView ) ) { + this._balloon.remove( this._mentionsView ); } - if ( this._isUIVisible ) { - this._balloon.remove( this._mentionsView ); + if ( this.editor.model.markers.has( 'mention' ) ) { + this.editor.model.change( writer => writer.removeMarker( 'mention' ) ); } // Make the last matched position on panel view undefined so the #_getBalloonPanelPositionData() method will return all positions diff --git a/tests/mention-integration.js b/tests/mention-integration.js index e71933c..24a7f32 100644 --- a/tests/mention-integration.js +++ b/tests/mention-integration.js @@ -3,18 +3,23 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ -/* global document */ +/* global document, setTimeout */ import BlockQuote from '@ckeditor/ckeditor5-block-quote/src/blockquote'; import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard'; import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; +import Table from '@ckeditor/ckeditor5-table/src/table'; +import TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar'; import UndoEditing from '@ckeditor/ckeditor5-undo/src/undoediting'; import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import { parse as parseView, getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view'; +import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import MentionEditing from '../src/mentionediting'; +import Mention from '../src/mention'; +import MentionUI from '../src/mentionui'; describe( 'Mention feature - integration', () => { let div, editor, model, doc; @@ -208,4 +213,59 @@ describe( 'Mention feature - integration', () => { .to.equal( expectedData ); } ); } ); + + describe( 'with table toolbar', () => { + beforeEach( () => { + return ClassicTestEditor + .create( div, { + plugins: [ Paragraph, Table, TableToolbar, Mention ], + table: { + contentToolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells' ] + }, + mention: { + feeds: [ + { + marker: '@', + feed: [ '@Barney', '@Lily', '@Marshall', '@Robin', '@Ted' ] + } + ] + } + } ) + .then( newEditor => { + editor = newEditor; + model = editor.model; + doc = model.document; + } ); + } ); + + it( 'should work with table toolbar', () => { + editor.ui.focusTracker.isFocused = true; + + setData( model, 'foo []
' ); + + const balloon = editor.plugins.get( 'ContextualBalloon' ); + const panelView = balloon.view; + const mentionUI = editor.plugins.get( MentionUI ); + const mentionsView = mentionUI._mentionsView; + + return new Promise( resolve => setTimeout( resolve, 200 ) ) + .then( () => { + model.change( writer => { + writer.insertText( '@', doc.selection.getFirstPosition() ); + } ); + } ) + .then( () => new Promise( resolve => setTimeout( resolve, 200 ) ) ) + .then( () => { + expect( panelView.isVisible ).to.be.true; + expect( balloon.visibleView === mentionsView ).to.be.true; + + model.change( writer => { + writer.setSelection( doc.getRoot().getNodeByPath( [ 0, 0, 0, 0 ] ), '1' ); + } ); + + expect( panelView.isVisible ).to.be.true; + expect( balloon.visibleView === mentionsView ).to.be.false; + } ); + } ); + } ); } ); From bf18842c77a12a4c9483f5e760549db9bea7ea8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Tue, 21 May 2019 10:39:06 +0200 Subject: [PATCH 2/4] Hide panel on matched text inside other mention when UI is still waiting for a feed. --- src/mentionui.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mentionui.js b/src/mentionui.js index 4787ee5..0d220af 100644 --- a/src/mentionui.js +++ b/src/mentionui.js @@ -296,6 +296,8 @@ export default class MentionUI extends Plugin { const nodeBefore = focus.nodeBefore; if ( hasMention || nodeBefore && nodeBefore.is( 'text' ) && nodeBefore.hasAttribute( 'mention' ) ) { + this._hideUIAndRemoveMarker(); + return; } From 59dfd342738cac12a68dce22360745e367d30514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Tue, 21 May 2019 13:04:40 +0200 Subject: [PATCH 3/4] Fix balloon position target function to not operate on graveyard ranges. --- src/mentionui.js | 10 ++++++- tests/mention-integration.js | 58 ++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/mentionui.js b/src/mentionui.js index 0d220af..2bc4d91 100644 --- a/src/mentionui.js +++ b/src/mentionui.js @@ -450,14 +450,22 @@ export default class MentionUI extends Plugin { * @private */ _getBalloonPanelPositionData( mentionMarker, preferredPosition ) { + const editor = this.editor; const editing = this.editor.editing; const domConverter = editing.view.domConverter; const mapper = editing.mapper; return { target: () => { - const viewRange = mapper.toViewRange( mentionMarker.getRange() ); + let modelRange = mentionMarker.getRange(); + + // Target the UI to the model selection range - the marker has been removed so probably the UI will not be shown anyway. + // The logic is used by ContextualBalloon to display another panel in the same place. + if ( modelRange.start.root.rootName == '$graveyard' ) { + modelRange = editor.model.document.selection.getFirstRange(); + } + const viewRange = mapper.toViewRange( modelRange ); const rangeRects = Rect.getDomRangeRects( domConverter.viewRangeToDom( viewRange ) ); return rangeRects.pop(); diff --git a/tests/mention-integration.js b/tests/mention-integration.js index 24a7f32..2091958 100644 --- a/tests/mention-integration.js +++ b/tests/mention-integration.js @@ -11,6 +11,8 @@ import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; import Table from '@ckeditor/ckeditor5-table/src/table'; import TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar'; import UndoEditing from '@ckeditor/ckeditor5-undo/src/undoediting'; +import Link from '@ckeditor/ckeditor5-link/src/link'; +import Delete from '@ckeditor/ckeditor5-typing/src/delete'; import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; @@ -268,4 +270,60 @@ describe( 'Mention feature - integration', () => { } ); } ); } ); + + describe( 'with link toolbar', () => { + beforeEach( () => { + return ClassicTestEditor + .create( div, { + plugins: [ Paragraph, Link, Delete, Mention ], + mention: { + feeds: [ + { + marker: '@', + feed: [ '@Barney', '@Lily', '@Marshall', '@Robin', '@Ted' ] + } + ] + } + } ) + .then( newEditor => { + editor = newEditor; + model = editor.model; + doc = model.document; + } ); + } ); + + it( 'should work with link toolbar', () => { + editor.ui.focusTracker.isFocused = true; + + setData( model, '[]' ); + + const balloon = editor.plugins.get( 'ContextualBalloon' ); + const panelView = balloon.view; + const mentionUI = editor.plugins.get( MentionUI ); + const mentionsView = mentionUI._mentionsView; + + return new Promise( resolve => setTimeout( resolve, 200 ) ) + .then( () => { + // Show link UI + editor.execute( 'link', '@' ); + editor.editing.view.document.fire( 'click' ); + + expect( panelView.isVisible ).to.be.true; + expect( balloon.visibleView === mentionsView ).to.be.false; // LinkUI + + model.change( writer => { + writer.setSelection( doc.getRoot().getChild( 0 ), 'end' ); + } ); + } ) + .then( () => new Promise( resolve => setTimeout( resolve, 200 ) ) ) + .then( () => { + expect( panelView.isVisible ).to.be.true; + expect( balloon.visibleView === mentionsView ).to.be.true; + + editor.execute( 'delete' ); + + expect( panelView.isVisible ).to.be.false; + } ); + } ); + } ); } ); From 3e7df96c37ade5124ce5155ac56860a2a5e8e918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Wed, 22 May 2019 12:09:42 +0200 Subject: [PATCH 4/4] Add missing dependencies. --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index eaba9a1..2040562 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,10 @@ "@ckeditor/ckeditor5-editor-classic": "^12.1.0", "@ckeditor/ckeditor5-engine": "^13.1.0", "@ckeditor/ckeditor5-font": "^11.1.0", + "@ckeditor/ckeditor5-link": "^11.0.1", "@ckeditor/ckeditor5-paragraph": "^11.0.1", + "@ckeditor/ckeditor5-table": "^12.0.1", + "@ckeditor/ckeditor5-typing": "^12.0.1", "@ckeditor/ckeditor5-undo": "^11.0.1", "@ckeditor/ckeditor5-widget": "^11.0.1", "eslint": "^5.5.0",