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

How to add attributes to injected HTML - e.g. target=_blank on a link? #760

Closed
thedavidmeister opened this issue Jan 7, 2018 · 11 comments
Closed
Labels
type:question This issue asks a question (how to...).

Comments

@thedavidmeister
Copy link

🐞 Is this a bug report or feature request? (choose one)

support

πŸ’» Version of CKEditor

alpha2

πŸ“‹ Steps to reproduce

  1. create links in the WYSIWYG

βœ… Expected result

links open in a new tab

❎ Actual result

links open in current tab

πŸ“ƒ Other details that might be useful

just not sure how to do this?

@Reinmar
Copy link
Member

Reinmar commented Jan 8, 2018

Do you mean changing the format how the official link plugin editor produces all links?

Or do you mean some new feature, e.g. a checkbox in the link balloon?

@thedavidmeister
Copy link
Author

@Reinmar whatever you think makes sense?

i'd be happy with a simple config change or similar that allows me to force all links to be external at the code level

@stephanvierkant
Copy link

stephanvierkant commented Jan 10, 2018

And what if you want to use _self, _parent or _top? Or if you want to set type, rel or referrerpolicy?

I don't agree with @thedavidmeister. It should be configurable per link, or (if this is considered out of scope), it's up to the developer to force the links to use "target=_blank" (using js, or modifying the HTML).

@Reinmar
Copy link
Member

Reinmar commented Jan 10, 2018

OK, that's why I asked :D Because there are two cases here:

  • you want to change the output of the existing link feature,
  • you want a new feature which extends the existing link feature.

Extending existing features

Adding features like the ability to set link's target, type orrel requires two things:

  • extending the existing UI (e.g. adding a dropdown or something),
  • extending how the new piece of data is converted back and forth between the model and the view.

The first task is very contextual, so different approaches need to be applied to different cases. Sometimes you'll want to implement your own new UI from scratch, sometimes you'll want to add a new input to the existing UI, sometimes you don't need a UI but some integration with your backend/whatever. What helps here is that features are implemented in a pretty modular way. We call it a "feature split" and it's under refactoring right now so we're inconsistent here and the existing code is imperfect. You can read more about it in #488 and #425.

The second task is supported by the conversion mechanism through its event-based nature and so-called conversion dispatchers (which let you convert each attribute and node separately). You can e.g. use the existing link plugin and add your own plugin which will support converting type attribute on existing links.

Unfortunately, the involved APIs are also being refactored as we speak and I'm unable to point you to the documentation. Both, API guides and proper architecture guides will be written as soon as we stabilise these concepts. Right now I can only send you to the source code but with a warning that what was released in alpha 2 looks very different than what we have right now.

Changing features behaviour

If you want the link feature to produce a different HTML output, which better match your needs then:

  • Consider doing this outside the editor. Treat editor's output as a normalised content representation and process it before sending it to the user. You can easily add target attribute to all links in the content produced by the editor using some HTML processing library. I know that e.g. Drupal does that. E.g. they make CKEditor 4 produce images as custom <image data-image-ref="<id>". ...> elements and then replace them with real <img>s with srcsets, etc. But the control over how the image is rendered to the user is on the Drupal side, which lets them e.g. render that image differently for different mediums.
  • Add an additional converter which adds type to all <a> elements.
  • Change feature's configuration. This is something new that we introduced first in ckeditor5-font and we'll be adding in other features. In short, a feature exposes a config option which lets you change its representation in the view (so also the produced data) by using a declarative format. It's all based on these conversion helpers and will allow developers to quickly change the output/input without writing any new plugins.

Unfortunately, as in case of extending features, this is also all under development and will be released and documented soon.

@Reinmar Reinmar changed the title how to add attributes to injected HTML - e.g. target=_blank on a link? How to add attributes to injected HTML - e.g. target=_blank on a link? Jan 10, 2018
@Reinmar Reinmar added type:question This issue asks a question (how to...). status:discussion and removed status:pending labels Jan 10, 2018
@thedavidmeister
Copy link
Author

ok well cool that it is under development.

i feel like my original question got a bit scope creeped here to be a more general feature discussion...

i had assumed (wrongly) that adding an html attribute to output would be straightforward and i was just misunderstanding something, seems like this is all still WIP.

for my use case i'm happy for target _blank only and for it to be applied to all link HTML strings generated by the editor - in that context it does seem like a simple callback to process links as they are generated would be handy (or something else similar).

@scofalik
Copy link
Contributor

scofalik commented Jan 11, 2018

I'll add one more option to ones presented by @Reinmar under "changing feature behavior".

If you want same behavior, each time a link is added, without any additional UI, then you could also introduce a plugin that will add an additional attribute whenever link is inserted.

First, you would have to specify a new attribute for $text in Schema. It might be called linkTarget.

Second, you would need to add a callback on model.Document#event:change that will listen to links addition (setting attribute linkHref) and add linkTarget on same range. You might take a look at image caption plugin, which implements same thing -- it adds caption element, whenever image is added to the editor. Of course, add it only if the range does not have that attribute yet (it may have it if the data is read from a database when it was previously saved).

Third, you would need to provide a simple converter for that attribute. That could be done through buildModelConverter and buildViewConverter.

This all, however, will change pretty soon, and will be simpler, but quite different, so I'd just hold on for now.

@thedavidmeister
Copy link
Author

ok np, this one is not urgent so i'll hold out til after API changes

@Reinmar
Copy link
Member

Reinmar commented Jan 11, 2018

i had assumed (wrongly) that adding an html attribute to output would be straightforward and i was just misunderstanding something, seems like this is all still WIP.

I'm not sure if this falls into straightforward, but that's the code you'd need today:

		data.modelToView.on( 'attribute:linkHref:$text', ( evt, data, consumable, conversionApi ) => {
			if ( !data.attributeNewValue ) {
				return;
			}

			const viewRange = conversionApi.mapper.toViewRange( data.range );

			const linkElement = new LinkElement( 'a', { target: '_blank' } );
			linkElement.priority = 5;

			viewWriter.wrap( viewRange, linkElement );
		} );

This makes editor.getData() output nice links:

image

There are some uncool things in this code, but I'll not go into that now since it may change.

So, that's for now. In the future adding this target attribute might be a change in the config property of the editor.


@scofalik You overcomplicated this topic :P You don't need another model attribute if all links should have this attribute. A link is now represented in the model by the linkHref attribute and that's a sufficient information. It's only about the view representation of this feature.

@scofalik
Copy link
Contributor

That's true, I thought that bringing new converter will be more difficult, but the link's default converter is very simple, so yeah, this converter is actually quite simple.

@Reinmar
Copy link
Member

Reinmar commented Jul 18, 2018

@mlewand
Copy link
Contributor

mlewand commented Jul 22, 2019

Recently we added the link decorators feature designed to solve that (and any other link attribute), see the Custom link attributes (decorators) section in our documentation for more information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:question This issue asks a question (how to...).
Projects
None yet
Development

No branches or pull requests

5 participants