From 926447c24fd0a6144eb33b8fe300623648f3c7f2 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Wed, 10 Jun 2020 15:04:47 +0200 Subject: [PATCH 1/7] The Link feature will insert a selection after modified/added text node instead of selecting them. --- packages/ckeditor5-link/src/linkcommand.js | 14 ++++++++++---- packages/ckeditor5-link/tests/linkcommand.js | 16 ++++++++-------- packages/ckeditor5-link/tests/manual/link.md | 7 +++++-- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/packages/ckeditor5-link/src/linkcommand.js b/packages/ckeditor5-link/src/linkcommand.js index cf4c24d9f82..fc1d9587c76 100644 --- a/packages/ckeditor5-link/src/linkcommand.js +++ b/packages/ckeditor5-link/src/linkcommand.js @@ -172,8 +172,8 @@ export default class LinkCommand extends Command { writer.removeAttribute( item, linkRange ); } ); - // Create new range wrapping changed link. - writer.setSelection( linkRange ); + // Put the selection at the end of the updated link. + writer.setSelection( writer.createPositionAfter( linkRange.end.nodeBefore ) ); } // If not then insert text node with `linkHref` attribute in place of caret. // However, since selection in collapsed, attribute value will be used as data for text node. @@ -191,9 +191,15 @@ export default class LinkCommand extends Command { model.insertContent( node, position ); - // Create new range wrapping created node. - writer.setSelection( writer.createRangeOn( node ) ); + // Put the selection at the end of the inserted link. + writer.setSelection( writer.createPositionAfter( node ) ); } + + // Remove the `linkHref` attribute and all link decorators from the selection. + // It stops adding a new content into the link element. + [ 'linkHref', ...truthyManualDecorators, ...falsyManualDecorators ].forEach( item => { + writer.removeSelectionAttribute( item ); + } ); } else { // If selection has non-collapsed ranges, we change attribute on nodes inside those ranges // omitting nodes where the `linkHref` attribute is disallowed. diff --git a/packages/ckeditor5-link/tests/linkcommand.js b/packages/ckeditor5-link/tests/linkcommand.js index 6258031bf92..7ca1bc11084 100644 --- a/packages/ckeditor5-link/tests/linkcommand.js +++ b/packages/ckeditor5-link/tests/linkcommand.js @@ -351,12 +351,12 @@ describe( 'LinkCommand', () => { } ); describe( 'collapsed selection', () => { - it( 'should insert text with `linkHref` attribute, text data equal to href and select new link', () => { + it( 'should insert text with `linkHref` attribute, text data equal to href and put the selection after the new link', () => { setData( model, 'foo[]bar' ); command.execute( 'url' ); - expect( getData( model ) ).to.equal( 'foo[<$text linkHref="url">url]bar' ); + expect( getData( model ) ).to.equal( 'foo<$text linkHref="url">url[]bar' ); } ); it( 'should insert text with `linkHref` attribute, and selection attributes', () => { @@ -367,16 +367,16 @@ describe( 'LinkCommand', () => { command.execute( 'url' ); expect( getData( model ) ).to.equal( - '<$text bold="true">foo[<$text bold="true" linkHref="url">url]<$text bold="true">bar' + '<$text bold="true">foo<$text bold="true" linkHref="url">url<$text bold="true">[]bar' ); } ); - it( 'should update `linkHref` attribute and select whole link when selection is inside text with `linkHref` attribute', () => { + it( 'should update `linkHref` attribute (text with `linkHref` attribute) and put the selection after the node', () => { setData( model, '<$text linkHref="other url">foo[]bar' ); command.execute( 'url' ); - expect( getData( model ) ).to.equal( '[<$text linkHref="url">foobar]' ); + expect( getData( model ) ).to.equal( '<$text linkHref="url">foobar[]' ); } ); it( 'should not insert text with `linkHref` attribute when is not allowed in parent', () => { @@ -455,7 +455,7 @@ describe( 'LinkCommand', () => { command.execute( 'url', { linkIsFoo: true, linkIsBar: true, linkIsSth: true } ); expect( getData( model ) ).to - .equal( 'foo[<$text linkHref="url" linkIsBar="true" linkIsFoo="true" linkIsSth="true">url]bar' ); + .equal( 'foo<$text linkHref="url" linkIsBar="true" linkIsFoo="true" linkIsSth="true">url[]bar' ); } ); it( 'should add additional attributes to link when link is modified', () => { @@ -464,7 +464,7 @@ describe( 'LinkCommand', () => { command.execute( 'url', { linkIsFoo: true, linkIsBar: true, linkIsSth: true } ); expect( getData( model ) ).to - .equal( 'f[<$text linkHref="url" linkIsBar="true" linkIsFoo="true" linkIsSth="true">ooba]r' ); + .equal( 'f<$text linkHref="url" linkIsBar="true" linkIsFoo="true" linkIsSth="true">ooba[]r' ); } ); it( 'should remove additional attributes to link if those are falsy', () => { @@ -472,7 +472,7 @@ describe( 'LinkCommand', () => { command.execute( 'url', { linkIsFoo: false, linkIsBar: false } ); - expect( getData( model ) ).to.equal( 'foo[<$text linkHref="url">url]bar' ); + expect( getData( model ) ).to.equal( 'foo<$text linkHref="url">url[]bar' ); } ); } ); diff --git a/packages/ckeditor5-link/tests/manual/link.md b/packages/ckeditor5-link/tests/manual/link.md index c3f9485921c..5a5239df1af 100644 --- a/packages/ckeditor5-link/tests/manual/link.md +++ b/packages/ckeditor5-link/tests/manual/link.md @@ -7,7 +7,8 @@ 3. Check if balloon panel attached to the selection appeared. 4. Fill in `Link URL` input in the panel. 5. Click `Save` button. -6. Check if selected text is converted into a link. +6. Check if the selection is after the text that was converted into a link. +7. Typing should not modify the link node. ### Insert new link @@ -16,7 +17,8 @@ 3. Check if balloon panel attached to the selection appeared. 4. Fill in `Link URL` input in the panel. 5. Click `Save` button. -6. Check if new link with anchor text the same as url value has been inserted and selected. +6. Check if new link with anchor text the same as url value has been inserted. +7. Check if the selection is after the text node. Typing should not modify the node. ### Edit link @@ -25,6 +27,7 @@ 3. Change `Link URL` input value. 4. Click `Save` button. 5. Check if link href value has changed. +6. Check if the selection is after the updated text node. Typing should not modify the node. ### Keyboard support From 37c744a7faa0929c5633d4fa7bb5d7342d273076 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Tue, 16 Jun 2020 13:48:23 +0200 Subject: [PATCH 2/7] After clicking a link, the selection will be moved before/after if clicked in a boundary. --- packages/ckeditor5-link/src/linkediting.js | 70 ++++++- packages/ckeditor5-link/tests/linkediting.js | 196 +++++++++++++++++++ 2 files changed, 264 insertions(+), 2 deletions(-) diff --git a/packages/ckeditor5-link/src/linkediting.js b/packages/ckeditor5-link/src/linkediting.js index c3b87965266..f6d3d6274dd 100644 --- a/packages/ckeditor5-link/src/linkediting.js +++ b/packages/ckeditor5-link/src/linkediting.js @@ -8,13 +8,15 @@ */ import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; +import MouseObserver from '@ckeditor/ckeditor5-engine/src/view/observer/mouseobserver'; +import bindTwoStepCaretToAttribute from '@ckeditor/ckeditor5-engine/src/utils/bindtwostepcarettoattribute'; import LinkCommand from './linkcommand'; import UnlinkCommand from './unlinkcommand'; -import { createLinkElement, ensureSafeUrl, getLocalizedDecorators, normalizeDecorators } from './utils'; import AutomaticDecorators from './utils/automaticdecorators'; import ManualDecorator from './utils/manualdecorator'; -import bindTwoStepCaretToAttribute from '@ckeditor/ckeditor5-engine/src/utils/bindtwostepcarettoattribute'; import findLinkRange from './findlinkrange'; +import { createLinkElement, ensureSafeUrl, getLocalizedDecorators, normalizeDecorators } from './utils'; + import '../theme/link.css'; const HIGHLIGHT_CLASS = 'ck-link_selected'; @@ -104,6 +106,9 @@ export default class LinkEditing extends Plugin { // Change the attributes of the selection in certain situations after the link was inserted into the document. this._enableInsertContentSelectionAttributesFixer(); + + // Handle a click at the beginning/end of a link element. + this._enableClickingAfterLink(); } /** @@ -347,4 +352,65 @@ export default class LinkEditing extends Plugin { } ); }, { priority: 'low' } ); } + + /** + * Starts listening to {@link module:engine/view/document~Document#event:mousedown} and + * {@link module:engine/view/document~Document#event:selectionChange} and puts the selection before/after a link node + * if clicked at the beginning/ending of the link. + * + * The purpose of this action is to allow typing around the link node directly after a click. + * + * See https://github.com/ckeditor/ckeditor5/issues/1016. + * + * @private + */ + _enableClickingAfterLink() { + const editor = this.editor; + + editor.editing.view.addObserver( MouseObserver ); + + let clicked = false; + + // Detect the click. + this.listenTo( editor.editing.view.document, 'mousedown', () => { + clicked = true; + } ); + + // When the selection has changed... + this.listenTo( editor.editing.view.document, 'selectionChange', () => { + if ( !clicked ) { + return; + } + + // ...and it was caused by the click... + clicked = false; + + const selection = editor.model.document.selection; + + // ...and no text is selected... + if ( !selection.isCollapsed ) { + return; + } + + // ...and clicked text is the link... + if ( !selection.hasAttribute( 'linkHref' ) ) { + return; + } + + const position = selection.getFirstPosition(); + const linkRange = findLinkRange( position, selection.getAttribute( 'linkHref' ), editor.model ); + + // ...check whether clicked start/end boundary of the link. + // If so, remove the `linkHref` attribute. + if ( position.isTouching( linkRange.start ) || position.isTouching( linkRange.end ) ) { + editor.model.change( writer => { + writer.removeSelectionAttribute( 'linkHref' ); + + for ( const manualDecorator of editor.commands.get( 'link' ).manualDecorators ) { + writer.removeSelectionAttribute( manualDecorator.id ); + } + } ); + } + } ); + } } diff --git a/packages/ckeditor5-link/tests/linkediting.js b/packages/ckeditor5-link/tests/linkediting.js index b284083d673..94902c8ec43 100644 --- a/packages/ckeditor5-link/tests/linkediting.js +++ b/packages/ckeditor5-link/tests/linkediting.js @@ -15,6 +15,8 @@ import { getData as getModelData, setData as setModelData } from '@ckeditor/cked import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view'; import { isLinkElement } from '../src/utils'; import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard'; +import Typing from '@ckeditor/ckeditor5-typing/src/typing'; +import BoldEditing from '@ckeditor/ckeditor5-basic-styles/src/bold/boldediting'; /* global document */ @@ -851,4 +853,198 @@ describe( 'LinkEditing', () => { } ); } ); } ); + + // https://github.com/ckeditor/ckeditor5/issues/1016 + describe( 'typing around the link after a click', () => { + let editor; + + beforeEach( async () => { + editor = await ClassicTestEditor.create( element, { + plugins: [ Paragraph, LinkEditing, Enter, Typing, BoldEditing ], + link: { + decorators: { + isFoo: { + mode: 'manual', + label: 'Foo', + attributes: { + class: 'foo' + } + }, + isBar: { + mode: 'manual', + label: 'Bar', + attributes: { + target: '_blank' + } + } + } + } + } ); + + model = editor.model; + view = editor.editing.view; + } ); + + afterEach( async () => { + await editor.destroy(); + } ); + + it( 'should insert content after the link', () => { + setModelData( model, '<$text linkHref="url">Bar[]' ); + + editor.editing.view.document.fire( 'mousedown' ); + editor.editing.view.document.fire( 'selectionChange', { + newSelection: view.document.selection + } ); + + expect( getModelData( model ) ).to.equal( '<$text linkHref="url">Bar[]' ); + + editor.execute( 'input', { text: 'Foo' } ); + + expect( getModelData( model ) ).to.equal( '<$text linkHref="url">BarFoo[]' ); + } ); + + it( 'should insert content before the link', () => { + setModelData( model, '<$text linkHref="url">[]Bar' ); + + editor.editing.view.document.fire( 'mousedown' ); + editor.editing.view.document.fire( 'selectionChange', { + newSelection: view.document.selection + } ); + + expect( getModelData( model ) ).to.equal( '[]<$text linkHref="url">Bar' ); + + editor.execute( 'input', { text: 'Foo' } ); + + expect( getModelData( model ) ).to.equal( 'Foo[]<$text linkHref="url">Bar' ); + } ); + + it( 'should insert content to the link if clicked inside it', () => { + setModelData( model, '<$text linkHref="url">B[]ar' ); + + editor.editing.view.document.fire( 'mousedown' ); + editor.editing.view.document.fire( 'selectionChange', { + newSelection: view.document.selection + } ); + + expect( getModelData( model ) ).to.equal( '<$text linkHref="url">B[]ar' ); + + editor.execute( 'input', { text: 'ar. B' } ); + + expect( getModelData( model ) ).to.equal( '<$text linkHref="url">Bar. B[]ar' ); + } ); + + it( 'should insert content between two links (selection at the end of the first link)', () => { + setModelData( model, '<$text linkHref="foo">Foo[]<$text linkHref="bar">Bar' ); + + editor.editing.view.document.fire( 'mousedown' ); + editor.editing.view.document.fire( 'selectionChange', { + newSelection: view.document.selection + } ); + + expect( getModelData( model ) ).to.equal( + '<$text linkHref="foo">Foo[]<$text linkHref="bar">Bar' + ); + + editor.execute( 'input', { text: 'Foo' } ); + + expect( getModelData( model ) ).to.equal( + '<$text linkHref="foo">FooFoo[]<$text linkHref="bar">Bar' + ); + } ); + + it( 'should insert content between two links (selection at the beginning of the second link)', () => { + setModelData( model, '<$text linkHref="foo">Foo<$text linkHref="bar">[]Bar' ); + + editor.editing.view.document.fire( 'mousedown' ); + editor.editing.view.document.fire( 'selectionChange', { + newSelection: view.document.selection + } ); + + expect( getModelData( model ) ).to.equal( + '<$text linkHref="foo">Foo[]<$text linkHref="bar">Bar' + ); + + editor.execute( 'input', { text: 'Foo' } ); + + expect( getModelData( model ) ).to.equal( + '<$text linkHref="foo">FooFoo[]<$text linkHref="bar">Bar' + ); + } ); + + it( 'should not touch other attributes than `linkHref`', () => { + setModelData( model, '<$text bold="true" linkHref="url">Bar[]' ); + + editor.editing.view.document.fire( 'mousedown' ); + editor.editing.view.document.fire( 'selectionChange', { + newSelection: view.document.selection + } ); + + expect( getModelData( model ) ).to.equal( + '<$text bold="true" linkHref="url">Bar<$text bold="true">[]' + ); + + editor.execute( 'input', { text: 'Foo' } ); + + expect( getModelData( model ) ).to.equal( + '<$text bold="true" linkHref="url">Bar<$text bold="true">Foo[]' + ); + } ); + + it( 'should do nothing if the text was not clicked', () => { + setModelData( model, '<$text linkHref="url">Bar[]' ); + + editor.editing.view.document.fire( 'selectionChange', { + newSelection: view.document.selection + } ); + + expect( getModelData( model ) ).to.equal( '<$text linkHref="url">Bar[]' ); + } ); + + it( 'should do nothing if the selection is not collapsed after the click', () => { + setModelData( model, '[<$text linkHref="url">Bar]' ); + + editor.editing.view.document.fire( 'mousedown' ); + editor.editing.view.document.fire( 'selectionChange', { + newSelection: view.document.selection + } ); + + expect( getModelData( model ) ).to.equal( '[<$text linkHref="url">Bar]' ); + } ); + + it( 'should do nothing if the text is not a link', () => { + setModelData( model, '<$text bold="true">Bar[]' ); + + editor.editing.view.document.fire( 'mousedown' ); + editor.editing.view.document.fire( 'selectionChange', { + newSelection: view.document.selection + } ); + + expect( getModelData( model ) ).to.equal( '<$text bold="true">Bar[]' ); + } ); + + it( 'should remove manual decorators', () => { + model.schema.extend( '$text', { + allowIn: '$root', + allowAttributes: [ 'linkIsFoo', 'linkIsBar' ] + } ); + + setModelData( model, '<$text linkIsFoo="true" linkIsBar="true" linkHref="url">Bar[]' ); + + editor.editing.view.document.fire( 'mousedown' ); + editor.editing.view.document.fire( 'selectionChange', { + newSelection: view.document.selection + } ); + + expect( getModelData( model ) ).to.equal( + '<$text linkHref="url" linkIsBar="true" linkIsFoo="true">Bar[]' + ); + + editor.execute( 'input', { text: 'Foo' } ); + + expect( getModelData( model ) ).to.equal( + '<$text linkHref="url" linkIsBar="true" linkIsFoo="true">BarFoo[]' + ); + } ); + } ); } ); From 1029b25f4a676f457d80d2e1e81c23d1a2890d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Tue, 16 Jun 2020 15:01:06 +0200 Subject: [PATCH 3/7] Fix link protocol tests. --- packages/ckeditor5-link/tests/linkui.js | 36 +++++++++++++++---------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/packages/ckeditor5-link/tests/linkui.js b/packages/ckeditor5-link/tests/linkui.js index 1f09e43f672..721bcce17ec 100644 --- a/packages/ckeditor5-link/tests/linkui.js +++ b/packages/ckeditor5-link/tests/linkui.js @@ -8,7 +8,7 @@ import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard'; -import { setData as setModelData, getData as getModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; +import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view'; import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; @@ -939,7 +939,7 @@ describe( 'LinkUI', () => { expect( defaultProtocol ).to.equal( 'https://' ); - editor.destroy(); + return editor.destroy(); } ); } ); @@ -952,56 +952,64 @@ describe( 'LinkUI', () => { it( 'should not add a protocol to the local links even when `config.link.defaultProtocol` configured', () => { return createEditorWithDefaultProtocol( 'http://' ).then( ( { editor, formView } ) => { + const linkCommandSpy = sinon.spy( editor.commands.get( 'link' ), 'execute' ); formView.urlInputView.fieldView.value = '#test'; formView.fire( 'submit' ); - expect( formView.urlInputView.fieldView.value ).to.equal( '#test' ); + sinon.assert.calledWith( linkCommandSpy, '#test', sinon.match.any ); - editor.destroy(); + return editor.destroy(); } ); } ); it( 'should not add a protocol to the relative links even when `config.link.defaultProtocol` configured', () => { return createEditorWithDefaultProtocol( 'http://' ).then( ( { editor, formView } ) => { + const linkCommandSpy = sinon.spy( editor.commands.get( 'link' ), 'execute' ); formView.urlInputView.fieldView.value = '/test.html'; formView.fire( 'submit' ); - expect( formView.urlInputView.fieldView.value ).to.equal( '/test.html' ); + sinon.assert.calledWith( linkCommandSpy, '/test.html', sinon.match.any ); - editor.destroy(); + return editor.destroy(); } ); } ); it( 'should not add a protocol when given provided within the value even when `config.link.defaultProtocol` configured', () => { return createEditorWithDefaultProtocol( 'http://' ).then( ( { editor, formView } ) => { + const linkCommandSpy = sinon.spy( editor.commands.get( 'link' ), 'execute' ); formView.urlInputView.fieldView.value = 'http://example.com'; formView.fire( 'submit' ); expect( formView.urlInputView.fieldView.value ).to.equal( 'http://example.com' ); + sinon.assert.calledWith( linkCommandSpy, 'http://example.com', sinon.match.any ); - editor.destroy(); + return editor.destroy(); } ); } ); it( 'should use the "http://" protocol when it\'s configured', () => { return createEditorWithDefaultProtocol( 'http://' ).then( ( { editor, formView } ) => { + const linkCommandSpy = sinon.spy( editor.commands.get( 'link' ), 'execute' ); + formView.urlInputView.fieldView.value = 'ckeditor.com'; formView.fire( 'submit' ); - expect( formView.urlInputView.fieldView.value ).to.equal( 'http://ckeditor.com' ); + sinon.assert.calledWith( linkCommandSpy, 'http://ckeditor.com', sinon.match.any ); - editor.destroy(); + return editor.destroy(); } ); } ); it( 'should use the "http://" protocol when it\'s configured and form input value contains "www."', () => { return createEditorWithDefaultProtocol( 'http://' ).then( ( { editor, formView } ) => { + const linkCommandSpy = sinon.spy( editor.commands.get( 'link' ), 'execute' ); + formView.urlInputView.fieldView.value = 'www.ckeditor.com'; formView.fire( 'submit' ); - expect( formView.urlInputView.fieldView.value ).to.equal( 'http://www.ckeditor.com' ); + sinon.assert.calledWith( linkCommandSpy, 'http://www.ckeditor.com', sinon.match.any ); - editor.destroy(); + return editor.destroy(); } ); } ); @@ -1016,7 +1024,7 @@ describe( 'LinkUI', () => { '[<$text linkHref="http://ckeditor.com">ckeditor.com]' ); - editor.destroy(); + return editor.destroy(); } ); } ); @@ -1032,7 +1040,7 @@ describe( 'LinkUI', () => { '[<$text linkHref="mailto:email@example.com">email@example.com]' ); - editor.destroy(); + return editor.destroy(); } ); } ); @@ -1044,7 +1052,7 @@ describe( 'LinkUI', () => { expect( formView.urlInputView.fieldView.value ).to.equal( 'mailto:test@example.com' ); - editor.destroy(); + return editor.destroy(); } ); } ); } ); From edd53bdefe3613a15ea060d9afc5b8b208ec6271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Tue, 16 Jun 2020 15:04:22 +0200 Subject: [PATCH 4/7] Typo fix. --- packages/ckeditor5-link/src/linkui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ckeditor5-link/src/linkui.js b/packages/ckeditor5-link/src/linkui.js index 1e78a65f05e..9d982f454b9 100644 --- a/packages/ckeditor5-link/src/linkui.js +++ b/packages/ckeditor5-link/src/linkui.js @@ -160,7 +160,7 @@ export default class LinkUI extends Plugin { const { value } = formView.urlInputView.fieldView.element; // The regex checks for the protocol syntax ('xxxx://' or 'xxxx:') - // or non-word charecters at the begining of the link ('/', '#' etc.). + // or non-word characters at the beginning of the link ('/', '#' etc.). const isProtocolNeeded = !!defaultProtocol && !protocolRegExp.test( value ); const isEmail = emailRegExp.test( value ); From 4663902968f32668981f2d348fcf60a6262995a8 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Wed, 17 Jun 2020 10:32:46 +0200 Subject: [PATCH 5/7] Fixed a test after changing the selection after inserting a link. --- packages/ckeditor5-mention/tests/mention-integration.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ckeditor5-mention/tests/mention-integration.js b/packages/ckeditor5-mention/tests/mention-integration.js index 991326c8f7d..0b732eac0da 100644 --- a/packages/ckeditor5-mention/tests/mention-integration.js +++ b/packages/ckeditor5-mention/tests/mention-integration.js @@ -308,7 +308,8 @@ describe( 'Mention feature - integration', () => { editor.execute( 'link', '@' ); editor.editing.view.document.fire( 'click' ); - expect( panelView.isVisible ).to.be.true; + // The selection is after the link node. + expect( panelView.isVisible ).to.be.false; expect( balloon.visibleView === mentionsView ).to.be.false; // LinkUI model.change( writer => { From bde9bede9af3da4bd9c4513d4314881893020245 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Wed, 17 Jun 2020 10:34:51 +0200 Subject: [PATCH 6/7] Improved the comment. --- packages/ckeditor5-mention/tests/mention-integration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ckeditor5-mention/tests/mention-integration.js b/packages/ckeditor5-mention/tests/mention-integration.js index 0b732eac0da..8c80a8d5691 100644 --- a/packages/ckeditor5-mention/tests/mention-integration.js +++ b/packages/ckeditor5-mention/tests/mention-integration.js @@ -308,7 +308,7 @@ describe( 'Mention feature - integration', () => { editor.execute( 'link', '@' ); editor.editing.view.document.fire( 'click' ); - // The selection is after the link node. + // The selection is after the link node. See #1016. expect( panelView.isVisible ).to.be.false; expect( balloon.visibleView === mentionsView ).to.be.false; // LinkUI From 20fab62b3cb90d1ea750352290a1c83f79952cda Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Wed, 17 Jun 2020 12:00:03 +0200 Subject: [PATCH 7/7] Mention: 100% CC. --- .../ckeditor5-mention/tests/mention-integration.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/ckeditor5-mention/tests/mention-integration.js b/packages/ckeditor5-mention/tests/mention-integration.js index 8c80a8d5691..c93f2d3d2c7 100644 --- a/packages/ckeditor5-mention/tests/mention-integration.js +++ b/packages/ckeditor5-mention/tests/mention-integration.js @@ -304,12 +304,18 @@ describe( 'Mention feature - integration', () => { return new Promise( resolve => setTimeout( resolve, 200 ) ) .then( () => { + const model = editor.model; + // Show link UI editor.execute( 'link', '@' ); + // The link is not being selected after inserting it. We need to put the selection manually. See #1016. + model.change( writer => { + writer.setSelection( writer.createRangeOn( model.document.getRoot().getChild( 0 ).getChild( 0 ) ) ); + } ); + editor.editing.view.document.fire( 'click' ); - // The selection is after the link node. See #1016. - expect( panelView.isVisible ).to.be.false; + expect( panelView.isVisible ).to.be.true; expect( balloon.visibleView === mentionsView ).to.be.false; // LinkUI model.change( writer => {