-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
Allow setting link's target attribute (allow opening links in new tabs) #4829
Allow setting link's target attribute (allow opening links in new tabs) #4829
Comments
Hi, @itelmenko. We consider implementing this feature in the future. There is no strong ETA, though. All we can do at this moment is add the import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import {
downcastAttributeToElement
} from '@ckeditor/ckeditor5-engine/src/conversion/downcast-converters';
const linkElementSymbol = Symbol( 'linkElement' );
const linkTarget = '_blank';
class MyLinkTargetPlugin extends Plugin {
init() {
const editor = this.editor;
// Override the default downcast converter provided by the LinkEditing class.
editor.conversion.for( 'downcast' )
.add( downcastAttributeToElement( {
model: 'linkHref',
view: createLinkElement,
priority: 'high'
} ) );
}
}
function createLinkElement( href, writer ) {
const linkElement = writer.createAttributeElement( 'a', {
href,
target: linkTarget
}, { priority: 5 } );
writer.setCustomProperty( linkElementSymbol, true, linkElement );
return linkElement;
} Then you can simply use the plugin in editing initialization ClassicEditor
.create( document.querySelector( '#editor' ), {
plugins: [ ..., MyLinkTargetPlugin ]
} ); What sort of UI would you expect to do configure the link target? |
BTW: We're working on some conversion improvements to make the code shorter and to avoid overriding the default converter (which is not safe in the long run). |
Thanks @oleq for snippet!
How can I install it? Also it is interesting issue:
I use Laravel 5.6 (where laravel-mix use webpack 2.7.0) Is it webpack issue or ckeditor? |
Check out this guide https://ckeditor5.github.io/docs/nightly/ckeditor5/latest/builds/guides/development/installing-plugins.html
We also noticed certain issues with UglifyJs in https://github.com/ckeditor/ckeditor5-dev/issues/371 (Webpack 4.x uses it by default). ATM I'd rather recommend you to use |
Hi, I just found this topic while wondering how come it was not possible to add target to a link. @oleq, you asked what kind of UI was expected for this. Why not a simple drop down with the posssible values (https://www.w3schools.com/tags/att_a_target.asp). I guess the first implementation of this feature might not include framename as almost no one uses frame anymore anyway. This seems to me like a mandatory feature and when you see the awesome job you did for tables, it’s really a shame that links miss such a basic functionality. I really hope someone will find the time to implement this feature. |
I'm surprised that not every single user of CKEditor would like the option to open links in a new tab. Otherwise, every link in your app will break out of the app. Isn't this like a mandatory feature? |
It depends.
CKEditor 5 can't decide automatically what should be the behaviour. Therefore, there are three options:
The first option is something that we can implement, of course, and perhaps will. We just don't have this on the roadmap yet. The second option is what many CMS does. It's actually the best. The content output from CKEditor 5 is treated as abstract data. This data is stored in HTML format, but that's just a format (e.g. Markdown doesn't let you define |
I'm a bit confused by this explanation. Most of the time, ckeditor will be used to allow one or several users to enter and save content. Therefore it is the user who decides whether a sentence is bold, underlined or... a link opens in a new window or not. How could the system know whether the user wants the link to open in a new tab or not? If the underlying system should be able to do that, why wouldn't it be able to also decide whether a text is bold or not ? At the end, it's the user who decide, not the system (at least in my opinion but I could be wrong), otherwise, the whole formatting features would bebuseless. |
A follow up question ... This feature was available in CKEditor 4. Why was it removed from v5? Or was it just somehow decided that it wasn't important to implement early on? |
Our opinion
The question is – how can the user know that? Usually, normal users don't understand and/or care about such things. Plus, a system can do things consistently, based on predefined rules. Users won't do that. If you want all external links to be opened in a new tab (which is what most people want), you can automate this. As I see it this is the most common scenario and therefore that'd be our first step. However, I understand that in some specific scenarios where these really are users who make the final decision it needs to be possible to control this attribute via the balloon. That's also a feasible extension, but I'd consider this a second step.
A bit of both. When implementing CKEditor 5 we had to review the existing features and rethink most of them. CKEditor 4 (and CKEditor 3 and FCKeditor) have a long history of adding WYSIWYG features in a way which works for developers and for building websites, but makes less sense for normal users and from content semantics perspective. CKEditor 4 started turning into the WYSIWYM direction around 2013 and CKEditor 5 just follows that. It's a rich-text editor which allows WYSIWYM editing. The behaviour of links is just not part of content semantics and a technical detail which most users wouldn't normally care. Also, this happens to be in line with other modern editors – Quill, Prosemirror or Slate don't let you set the target as well. Markdown doesn't allow this too. But I said "a bit of both" because I don't say we would never implement it. It's just something that's nice to have (because in some cases it may be necessary), but wasn't there in the roadmap to 1.0.0. Feedback neededWhat I wrote above is how we think about it. We may be wrong regarding the priorities so, please vote:
Before voting please read this discussion starting from this comment up to this one. |
It's sorta funny you talk about other modern editors not having the link target feature, but you fail to talk about BY FAR the most common one out there ... the one that runs 30% of websites ... WordPress. If they ever got rid of link target ability there'd be riots lol. For anyone like myself using CKEditor in a SaaS, setting an optional link target is absolutely crucial. I can think of numerous other applications where it would be as well. I'm still quite surprised you haven't received many, many more complaints about this. You can probably tell that I of course voted for the "open link in a new tab" checkbox :) |
@Reinmar To have our backend parse every text and rewrite the a elements is not an option. |
@Reinmar When is the voting closed and the outcome presented ? When can we expect the checkbox option ?🙂 |
Note to ourselves: Let's update https://stackoverflow.com/questions/49366292/ckeditor-5-links-set-default-target-for-links-or-edit-target once we get this. |
Well I saw many votes on the checkbox option coming from Swedes (hello from Poland, BTW ;) and newly registered users on the very first day after I asked the question. Normalizing the results with that in mind I'd say it's a draw. Most importantly though, both options got votes, which means that both are worth being implemented. When? IDK yet. |
Can I ask why? |
Sure. We are using blank for different reasons. We are not able to use the url to determine if the blank should be used or not. internal or external links (or other url parts) does not help us. In our company this became a problem for quite a few. And some of them even registered here maybe :) Keep up the good work, we really like changes made between 4 and 5! |
This is exactly the same reason why users of our SaaS need the option to set certain links (but not all links) to open in a new tab.
FYI we've had to revert back to CKEditor 4 as this lack of functionality is a deal-breaker. |
As everyone seems to give use case for this, I'll add mine. We are using umbraco cms to allow content managers to create the content. However the site has some dynamic component made in angularjs. The problem is then that some sentence displayed by these content needs to be translated (text like "no result found". So I use the balloon editor to enable content manager to edit these label on the fly. In this label, managers can add link but the must be able to specify how the link opens... |
Related #1514. |
We actually would like to provide means to solve both approaches:
While thinking about API, this feature can actually be generalized and not limited to assigning targets only. Other use cases include So the common feature sounds more like link decorators. Configconfig.link.decorator = [
{
// Mode could be either manual or automatic.
mode: 'automatic',
callback: function( url ) {
// This should be a more precise regexp.
return url.startswith( 'https://' );
},
// This is a set of attribute applied to the link in view.
attributes: {
rel: 'noopener noreferrer',
target: '_blank'
}
},
{
mode: 'manual',
label: 'Force download', // Label for the checkbox.
attributes: {
download: 'download'
}
},
{
mode: 'automatic',
callback: function( url ) {
return url.includes( '/gallery/' ) && url.endswith( '.png' );
},
attributes: {
class: 'lightbox'
}
}
]; The config to manually handle config.link.decorator = [ {
mode: 'manual',
label: 'Open in a new window',
attributes: {
target: '_blank',
manualTarget: true
}
} ]; UIManual decorators should add a checkbox to the UI. We don't expect to extend this feature to provide other input controls (selects/radios). The simplest idea would be just to put them below the url input: One thing to remember here is to make sure that the tab order make sense after adding these controls. ModelIn case of manual decorators the feature will need to place the state in editor model. Simply generating a new unique attribute for each decorator sounds reasonable. So that e.g. There's no such need for the automatic decorators, as they're stateless and should be queried each time a model item is being converted to a view. Default behaviorAn open question remains whether we need to enable this by default? After thinking this case I believe that adding automatic decorator that would add In that case our documentation should contain listings for both solutions. |
👍 for opt-in and samples of as many solutions as possible. Other notes:
|
@mlewand, @Reinmar As I can see there isn't displayed any UI for range selection on links, even if those are entirely inside single link. However it's possible to execute command on such range, and behaviour in such cases really depends from selection range. Should this feature support somehow ranged selection, or be available exclusively for collapsed one and link creation from toolbar? |
It should do exactly the same thing which the link command does. It must be 1:1 synced with it. In fact, I think that perhaps we should extend the link command here to ensure it always applies all the attributes. |
Feature: Introduced styles for the decorators UI of the `LinkFormView` component (see ckeditor/ckeditor5-link#186).
Feature: Introduced configurable link decorators allowing customization of link attributes in the editor data. Closes #186.
This feature just got merged to the Basic configuration should looks something like that: ClassicEditor
.create( document.querySelector( '#editor' ), {
plugins: [ Link, Typing, Paragraph, Clipboard, Undo, Enter ],
toolbar: [ 'link', 'undo', 'redo' ],
link: {
decorators: {
isExternal: {
mode: 'manual',
label: 'Open in a new tab',
attributes: {
target: '_blank'
}
}
}
}
} ); More info will be available in the docs. |
Hi @mlewand. Thanks for implementing this feature. But it seems that upcast conversion for additional attributes is missing. |
Thanks for catching that! We're working hard to include it in the upcoming release, keep an eye on ckeditor/ckeditor5-link#233 for quickest update. |
I followed this tutorial and added the I'm using CKEditor5 Classic Build in Vue, version 12.3.1. |
@Nivekul What data (editor content) did you use? |
@oleq I'm not sure what is the data (editor content), but the following is how I setup the editor Template<ckeditor v-model="article" class="editor" :editor="editor" :config="editorConfig"
@focus="editorFocused=true" @input="handleEdit"></ckeditor> Dataarticle: '',
editor: ClassicEditor,
editorConfig: {
toolbar: {
items: [
'Heading', '|',
'bold', 'italic',
'link', 'blockQuote',
'ImageUpload',
'MediaEmbed',
]
},
link: {
addTargetToExternalLinks: true,
},
image: {
toolbar: ['imageStyle:alignLeft', 'imageStyle:full', 'imageStyle:alignRight', '|', 'imageTextAlternative'],
styles: ['full', 'alignLeft', 'alignRight'],
},
placeholder: 'Start writing your article here ...',
extraPlugins: [(editor) => this.uploadAdapter(editor, this)],
}, |
So what happens to links starting with "https://" or "http://" or "//" in your content? |
@oleq I see, it works now! Thanks! |
I felt compelled to come here and add a note that this feature is the cat's whiskers :-) What a fricking lifesaver to be able to put an auto rule that sends external links to a new window without having to worry about writers screwing the UX for readers. Thank you! CK editor is lovely, and thank you for listening to the community. |
link: { |
@mlewand do you have somewhere branch with your changes mentioned here: #4829 (comment) |
@Madejczyk I haven't set up any particular branch containing this configuration. All that is required is just some simple config adjustment. I made a demo so you can play with it: https://codepen.io/mlewand/pen/NWvooJg?editors=1010 |
See here |
It seems that the setting is reset:
(like indicated above) And I get this (video is slightly edited to shorten it and to make it clear where the page reloads) craft.ckeditor.mp4Is this normal? How would one fix this? |
Original ticket description
Feedback needed
Please read this discussion starting from this comment and leave your feedback (by adding a reaction) in this comment.
The text was updated successfully, but these errors were encountered: