Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GHS: "Learn from Link Plugin's" _enableClickingAfterLink – Add Cleanup Behavior For Custom Attributes bound to anchor elements #13594

Closed
mmichaelis opened this issue Mar 2, 2023 · 3 comments
Labels
resolution:expired This issue was closed due to lack of feedback. type:improvement This issue reports a possible enhancement of an existing feature.

Comments

@mmichaelis
Copy link

πŸ“ Provide a description of the improvement

The Suggestion

Extract code from linkediting.ts regarding _enableClickingAfterLink and re-use cleanup behavior when anchor tags are handled in GHS plugin. Thus, make it possible to also remove any attributes defined by GHS that are bound to anchor tags.

The bigger picture: As sketched in #9730, we hook into the link feature to add more behaviors to it. Like our own management of the target attribute (CKEditor's default solution is not enough for us). Currently, we have to copy, paste and adapt the code of _enableClickingAfterLink, while it would be much nicer to have an "approved" version by CKEditor-Team how to deal with these cleanups after repositioning the cursor.

The Issue

When you configure the GHS for anchor <a> tag to hold additional attributes, these attributes will not inherit the cleanup-logic from _enableClickingAfterLink:

private _enableClickingAfterLink(): void {
const editor = this.editor;
const model = editor.model;
editor.editing.view.addObserver( MouseObserver );
let clicked = false;
// Detect the click.
this.listenTo<ViewDocumentMouseDownEvent>( editor.editing.view.document, 'mousedown', () => {
clicked = true;
} );
// When the selection has changed...
this.listenTo<ViewDocumentSelectionChangeEvent>( editor.editing.view.document, 'selectionChange', () => {
if ( !clicked ) {
return;
}
// ...and it was caused by the click...
clicked = false;
const selection = 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 = findAttributeRange( position, 'linkHref', selection.getAttribute( 'linkHref' ), 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 ) ) {
model.change( writer => {
removeLinkAttributesFromSelection( writer, getLinkAttributesAllowedOnText( model.schema ) );
} );
}
} );
}

As a result, when clicking before or after a link, all other attributes will remain and the anchor element will be continued – while the link plugin won't detect it as link anymore, as it just checks for the linkHref attribute.

For a custom attribute data-xlink-type we have to add due to our data, this will result in editing view like this when placing the cursor in front of the link (can be observed in inspector very nicely):

<a data-xlink-type="">
  <!-- Cursor Position -->
</a>
<a href="https://example.org/">Lorem</a>

To push it to the limits, disable link plugin and position the cursor behind the link. You will notice, when typing, that the anchor is expanded. While this is a nice advertisement for the link feature to enable it, it seems to me, that this cleanup logic should be made available also to GHS.

πŸ“ƒ Other details

  • Browser: Chrome
  • OS: Windows
  • CKEditor version: 36.0.1
  • Installed CKEditor plugins: GHS, Link Plugin

If you'd like to see this improvement implemented, add a πŸ‘ reaction to this post.

@mmichaelis mmichaelis added the type:improvement This issue reports a possible enhancement of an existing feature. label Mar 2, 2023
@mmichaelis
Copy link
Author

In CoreMedia/ckeditor5-plugins#141 you will find a solution, that we will now use to work around this issue. The essential part of it is a plugin LinkAttributes which serves as API to register attributes to be handled as "belonging to a link" and thus, to be removed on "unlink" command and to benefit from two-caret-movement plugin.

API usage from plugins, for example:

getLinkAttributes(editor)?.registerAttribute({
  model: "linkCustomAttribute",
  view: "data-custom-attribute",
});

Also, a configuration API for CKEditor 5 instance creation is available:

const linkAttributesConfig: LinkAttributesConfig = {
  attributes: [
    { view: "title", model: "linkTitle" },
    { view: "data-xlink-actuate", model: "linkActuate" },
  ],
};

ClassicEditor.create(sourceElement, {
  plugins: [
    Link,
    LinkAttributes,
    /* ... */
  ],
  link: {
    defaultProtocol: "https://",
    ...linkAttributesConfig,
    /* ... */
  }
});

We think, a similar API may make sense to be provided by the CKEditor 5 Link feature along with a corresponding integration hook into GHS plugin.

@CKEditorBot
Copy link
Collaborator

There has been no activity on this issue for the past year. We've marked it as stale and will close it in 30 days. We understand it may still be relevant, so if you're interested in the solution, leave a comment or reaction under this issue.

@CKEditorBot
Copy link
Collaborator

We've closed your issue due to inactivity. We understand that the issue may still be relevant. If so, feel free to open a new one (and link this issue to it).

@CKEditorBot CKEditorBot added resolution:expired This issue was closed due to lack of feedback. and removed status:stale labels Apr 2, 2024
@CKEditorBot CKEditorBot closed this as not planned Won't fix, can't repro, duplicate, stale Apr 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
resolution:expired This issue was closed due to lack of feedback. type:improvement This issue reports a possible enhancement of an existing feature.
Projects
None yet
Development

No branches or pull requests

2 participants