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
Create a custom link button #4836
Comments
What do you mean? What do you want it to do? cc @oleq |
I want ot us the existing UI a button between the tow buttons in the UI would be the best solution. |
You can write a simple plugin to add a button to the existing UI. Check out https://docs.ckeditor.com/ckeditor5/latest/builds/guides/development/installing-plugins.html to learn how to extend existing editor build, create own editor builds, etc. import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import LinkUI from '@ckeditor/ckeditor5-link/src/linkui';
class InternalLink extends Plugin {
init() {
const editor = this.editor;
const linkUI = editor.plugins.get( LinkUI );
this.linkFormView = linkUI.formView;
this.button = this._createButton();
this.linkFormView.once( 'render', () => {
// Render button's tamplate.
this.button.render();
// Register the button under the link form view, it will handle its destruction.
this.linkFormView.registerChild( this.button );
// Inject the element into DOM.
this.linkFormView.element.insertBefore( this.button.element, this.linkFormView.saveButtonView.element );
} );
}
_createButton() {
const editor = this.editor;
const button = new ButtonView( this.locale );
const linkCommand = editor.commands.get( 'link' );
button.set( {
label: 'Internal link',
withText: true,
tooltip: true
} );
// Probably this button should be also disabled when the link command is disabled.
// Try setting editor.isReadOnly = true to see it in action.
button.bind( 'isEnabled' ).to( linkCommand );
button.on( 'execute', () => {
// Do something (like open the popup), then update the link URL field's value.
// The line below will be probably executed inside some callback.
this.linkFormView.urlInputView.value = 'http://some.internal.link';
} );
return button;
}
} |
@oleq thanks for your example!
What is wrong? |
Probably missing |
@jodator thanks! Now it works. @oleq your example works absolutely perfect! Thanks a lot! |
I have still one question about that. I want add the button optional. As options like
Also:
How i can modify the plugin to ensure it? |
Your plugin should define a config option in plugin's constructor, e.g. constructor( editor ) {
super( editor );
editor.config.define( 'link.rexlink', [ 'internal', 'media' ] );
} then in the const rexlinkConfig = editor.config.get( 'link.rexlink' );
if ( something about rexlinkConfig ) {
// create buttons or not
} ClassicEditor
.create( ...., {
link: {
rexlink: [ 'foo' ]
}
} )
.then( editor => {
window.editor = editor;
} )
.catch( err => {
console.error( err );
} ); |
Thanks @oleq thats work perfekt!
|
@joachimdoerr Check out https://github.com/ckeditor/ckeditor5-link/issues/73 and https://github.com/ckeditor/ckeditor5-link/issues/15. You can try listening to |
@oleq thanks for the event idee. For now I crate this solution that works for me
The next step is the image integration. I want to use the redaxo mediamanager to add images. In which repository can I open a issue about that? |
If I were you, I'd experiment with https://github.com/ckeditor/ckeditor5-link/issues/195#issuecomment-388057470. What you did in the last snippet could fail if one decided to change the text of the link later on and then insert the same URL somewhere else because (if I got it correctly) it blindly seeks certain
Check out https://docs.ckeditor.com/ckeditor5/latest/api/adapter-ckfinder.html |
Sorry for replying to this closed issue, but I'm currently facing the same problem. Is there a different way to add a custom button to the link dialog now? |
@JanWennrichPCSG ckeditor v36 lazily creates the form view so I took a different approach. It's a bit hacky… I override the import {Plugin} from '@ckeditor/ckeditor5-core';
import {Link, LinkUI} from "@ckeditor/ckeditor5-link";
import {addListToDropdown, ButtonView, createDropdown, Model, View} from "@ckeditor/ckeditor5-ui";
import {Collection} from "@ckeditor/ckeditor5-utils";
export default class CraftLink extends Plugin {
constructor(editor) {
super(editor);
editor.config.define('craftLink', {
assetModal: {
sources: null,
condition: null,
criteria: null,
defaultSiteId: null,
storageKey: null,
},
entryModal: {
sources: null,
condition: null,
criteria: null,
defaultSiteId: null,
storageKey: null,
}
});
}
static get requires() {
return [Link];
}
static get pluginName() {
return 'CraftLink';
}
init() {
this.linkUI = this.editor.plugins.get(LinkUI);
this._addFormViewButtons();
}
_addFormViewButtons() {
const editor = this.editor;
const t = editor.t;
const _createFormViewOriginal = this.linkUI._createFormView;
this.linkUI._createFormView = () => {
const formView = _createFormViewOriginal.bind(this.linkUI).call();
const linkToAssetButton = new ButtonView();
const linkToEntryButton = new ButtonView();
linkToAssetButton.set({
label: t('Link to an Asset'),
withText: true,
_elementType: 'craft\\elements\\Asset',
_refHandle: 'asset',
_commandName: 'craftLinkElementCommand',
});
linkToAssetButton.on('execute', (evt) => {
this._openModal({
elementType: evt.source._elementType,
refHandle: evt.source._refHandle
})
});
linkToEntryButton.set({
label: t('Link to an Entry'),
withText: true,
_elementType: 'craft\\elements\\Entry',
_refHandle: 'entry',
_commandName: 'craftLinkElementCommand',
});
linkToEntryButton.on('execute', (evt) => {
this._openModal({
elementType: evt.source._elementType,
refHandle: evt.source._refHandle
})
});
const dividerView = new View();
dividerView.setTemplate({
tag: 'div',
attributes: {
class: ['ck', 'ck-reset'],
style: {
margin: '4px',
borderLeft: '1px solid var(--ck-color-base-border)'
}
}
});
const additionalButtonsView = new View();
additionalButtonsView.setTemplate({
tag: 'div',
attributes: {
class: ['ck', 'ck-reset'],
style: {
display: 'flex',
alignItems: 'stretch',
justifyContent: 'center',
padding: 'var(--ck-spacing-small)',
borderBottom: '1px solid var(--ck-color-base-border)'
}
},
children: [linkToAssetButton, dividerView, linkToEntryButton]
});
formView.template.children.unshift(additionalButtonsView);
formView.template.attributes.class.push('ck-link-form_layout-vertical');
return formView;
}
}
_openModal(args) {
const modalSettings = this.editor.config.get(`craftImage.${args.refHandle}Modal`);
Craft.createElementSelectorModal(args.elementType, {
...modalSettings,
onCancel: () => {
this.editor.editing.view.focus();
},
onSelect: (elements) => {
if (!elements.length) {
return;
}
const [element] = elements;
const url = `${element.url}#${args.refHandle}:${element.id}@${element.siteId}`;
this.editor.editing.view.focus();
this.linkUI._showUI(true);
this.linkUI.formView.urlInputView.fieldView.element.value = url;
setTimeout(() => {
this.linkUI.formView.urlInputView.fieldView.element.focus();
}, 100)
},
closeOtherModals: false
});
}
} Then you get something like: |
Here is an updated version of the solution: import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import LinkUI from '@ckeditor/ckeditor5-link/src/linkui';
class InternalLink extends Plugin {
init() {
const editor = this.editor;
const linkUI = editor.plugins.get( LinkUI );
const contextualBalloonPlugin = editor.plugins.get( 'ContextualBalloon' );
this.listenTo( contextualBalloonPlugin, 'change:visibleView', ( evt, name, visibleView ) => {
if ( visibleView === linkUI.formView ) {
// Detach the listener.
this.stopListening( contextualBalloonPlugin, 'change:visibleView' );
this.linkFormView = linkUI.formView;
this.button = this._createButton();
console.log( 'The link form view has been displayed', this.linkFormView );
// Render button's tamplate.
this.button.render();
// Register the button under the link form view, it will handle its destruction.
this.linkFormView.registerChild( this.button );
// Inject the element into DOM.
this.linkFormView.element.insertBefore( this.button.element, this.linkFormView.saveButtonView.element );
}
} );
}
_createButton() {
const editor = this.editor;
const button = new ButtonView( this.locale );
const linkCommand = editor.commands.get( 'link' );
button.set( {
label: 'Internal link',
withText: true,
tooltip: true
} );
// Probably this button should be also disabled when the link command is disabled.
// Try setting editor.isReadOnly = true to see it in action.
button.bind( 'isEnabled' ).to( linkCommand );
button.on( 'execute', () => {
// Do something (like open the popup), then update the link URL field's value.
// The line below will be probably executed inside some callback.
this.linkFormView.urlInputView.value = 'http://some.internal.link';
} );
return button;
}
} |
How i can create a custom link button for a CMS implementation?
The text was updated successfully, but these errors were encountered: