Skip to content

Commit 38979ed

Browse files
authored
Merge pull request #12460 from ckeditor/ck/11040-auto-link-correction
Fix (link): Fixed incorrect behavior when text before auto-linked url was removed by pressing backspace. Previously, the removed text was reinserted on backspace press. Closes #12447.
2 parents d9500fe + fb0e1fc commit 38979ed

File tree

2 files changed

+57
-6
lines changed

2 files changed

+57
-6
lines changed

packages/ckeditor5-link/src/autolink.js

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -223,26 +223,39 @@ export default class AutoLink extends Plugin {
223223
}
224224

225225
/**
226-
* Applies a link on a given range.
226+
* Applies a link on a given range if the link should be applied.
227227
*
228228
* @param {String} url The URL to link.
229229
* @param {module:engine/model/range~Range} range The text range to apply the link attribute to.
230230
* @private
231231
*/
232-
_applyAutoLink( link, range ) {
232+
_applyAutoLink( url, range ) {
233233
const model = this.editor.model;
234-
const deletePlugin = this.editor.plugins.get( 'Delete' );
235234

236235
const defaultProtocol = this.editor.config.get( 'link.defaultProtocol' );
237-
const parsedUrl = addLinkProtocolIfApplicable( link, defaultProtocol );
236+
const fullUrl = addLinkProtocolIfApplicable( url, defaultProtocol );
238237

239-
if ( !this.isEnabled || !isLinkAllowedOnRange( range, model ) || !linkHasProtocol( parsedUrl ) ) {
238+
if ( !this.isEnabled || !isLinkAllowedOnRange( range, model ) || !linkHasProtocol( fullUrl ) || linkIsAlreadySet( range ) ) {
240239
return;
241240
}
242241

242+
this._persistAutoLink( fullUrl, range );
243+
}
244+
245+
/**
246+
* Enqueues autolink changes in the model.
247+
*
248+
* @param {String} url The URL to link.
249+
* @param {module:engine/model/range~Range} range The text range to apply the link attribute to.
250+
* @protected
251+
*/
252+
_persistAutoLink( url, range ) {
253+
const model = this.editor.model;
254+
const deletePlugin = this.editor.plugins.get( 'Delete' );
255+
243256
// Enqueue change to make undo step.
244257
model.enqueueChange( writer => {
245-
writer.setAttribute( 'linkHref', parsedUrl, range );
258+
writer.setAttribute( 'linkHref', url, range );
246259

247260
model.enqueueChange( () => {
248261
deletePlugin.requestUndoOnBackspace();
@@ -265,3 +278,8 @@ function getUrlAtTextEnd( text ) {
265278
function isLinkAllowedOnRange( range, model ) {
266279
return model.schema.checkAttributeInSelection( model.createSelection( range ), 'linkHref' );
267280
}
281+
282+
function linkIsAlreadySet( range ) {
283+
const item = range.start.nodeAfter;
284+
return item && item.hasAttribute( 'linkHref' );
285+
}

packages/ckeditor5-link/tests/autolink.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,17 @@ describe( 'AutoLink', () => {
246246
);
247247
} );
248248

249+
it( 'does not autolink if link is already created', () => {
250+
setData( model, '<paragraph><$text linkHref="http://www.cksource.com">http://www.cksource.com</$text>[]</paragraph>' );
251+
252+
const plugin = editor.plugins.get( 'AutoLink' );
253+
const spy = sinon.spy( plugin, '_persistAutoLink' );
254+
255+
editor.execute( 'enter' );
256+
257+
sinon.assert.notCalled( spy );
258+
} );
259+
249260
// Some examples came from https://mathiasbynens.be/demo/url-regex.
250261
describe( 'supported URL', () => {
251262
const supportedURLs = [
@@ -414,6 +425,28 @@ describe( 'AutoLink', () => {
414425
'<paragraph>https://www.cksource.com []</paragraph>'
415426
);
416427
} );
428+
429+
// https://github.com/ckeditor/ckeditor5/issues/12447
430+
it( 'should not undo auto-linking by pressing backspace after any other change has been made', () => {
431+
const viewDocument = editor.editing.view.document;
432+
const deleteEvent = new DomEventData(
433+
viewDocument,
434+
{ preventDefault: sinon.spy() },
435+
{ direction: 'backward', unit: 'codePoint', sequence: 1 }
436+
);
437+
438+
simulateTyping( ' abc' );
439+
440+
viewDocument.fire( 'delete', deleteEvent );
441+
viewDocument.fire( 'delete', deleteEvent );
442+
viewDocument.fire( 'delete', deleteEvent );
443+
viewDocument.fire( 'delete', deleteEvent );
444+
viewDocument.fire( 'delete', deleteEvent );
445+
446+
expect( getData( model ) ).to.equal(
447+
'<paragraph><$text linkHref="https://www.cksource.com">https://www.cksource.co[]</$text></paragraph>'
448+
);
449+
} );
417450
} );
418451

419452
describe( 'Code blocks integration', () => {

0 commit comments

Comments
 (0)