How to set On Off state for CKEditor custom button - javascript

I have added a custom plugin to CKEditor inline to perform bold operation. The plugin is working as expected but the on/off state of button is not working.
When command is executed its state is always TRISTATE_OFF.
CKEDITOR.plugins.add( 'customBold', {
requires: 'toolbar',
icons: 'bold',
hidpi: false,
init: function( editor ) {
var boldCommand = {
exec: function( editor ) {
document.execCommand('bold', false, null);
}
}
editor.addCommand( 'bold', boldCommand );
editor.ui.addButton && editor.ui.addButton( 'Bold', {
label: 'bold',
command: 'bold',
toolbar: 'basic,10'
});
editor.setKeystroke( [
[ CKEDITOR.CTRL + 66 /*B*/, 'bold' ]
]);
}
});
When user selects the bold text I would like to toggle the bold style in toolbar.

You need to call the command.setState method which will set the state of the command which then automatically affects the state of related button.
However, you need to know when to call that method (when the state changes). CKEditor's plugins like the basicstyle plugin use the CKEditor's styles system which let them easily listen on style state changes:
editor.attachStyleStateChange( style, function( state ) {
!editor.readOnly && editor.getCommand( commandName ).setState( state );
} );
You, however, try to use the native commands, which I highly recommend not to. It is not a coincidence that CKEditor implements its own style system and its own commands.

I'm answering this purely because this result constantly came up when I was looking how to apply a style to a CKEditor custom plugin button on the toolbar.
This ended up being fairly simple, although not especially elegant.
Currently, I do my own handling of CKEditor buttons (outside of the plugin.js files). This is because I'm using CKEditor to dynamically create editor instances, which it doesn't seem very well suited to do and I often have to override functions.
Here's how I apply a style to a 'active' button in the editor on the myplugin button action:
//Catch the initial click
$('.parent_element').on('click', '.cke_button__myplugin', function(){
//Apply a gradiant style to the button
$('.cke_button__myplugin').css({'background':' radial-gradient(#FFF, #6E6E6E)'})
//Logic to handle button click
});
This way, you simply apply a style to the button without having to toggle the actual button.png

Related

Get current selection info from Froala editor

I am using Froala WYSIWYG editor in my project. I would like to create my own font-family select component which will display the current font-family. So I need to listen to changes of an editor's selection, each time get current font-family and update my custom component.
import "froala-editor/js/plugins/font_family.min.js";
import Froala from "froala-editor";
const editor = new Froala("#container", {
events: {
onSelectionChange: function() { // I need something like this.
console.log(this.selection.get().fontFamily); // Eg. "Arial" or "Verdana".
}
}
});
I only found fontFamilySelection option in the docs, however, it will show the current font family in a native editor's component. One way is to read the current font family from the native component, but it's not a very clean solution.
Is there any way to do something like this?
Try these three additional event hooks
input - on user input
click - after clicking somewhere in the editor, perhaps into a different tag and font
commands.after - after any menu command, like the native font picker
These hooks allow you to query the font-family style on the current tag.
const editor = new Froala("#container", {
events: {
onSelectionChange: function() { // I need something like this.
console.log(this.selection.get().fontFamily); // Eg. "Arial" or "Verdana".
},
'input': function (inputEvent) {
// after a user input
console.log(this.selection.element().style.fontFamily);
},'click': function (clickEvent) {
// after a user click
console.log(this.selection.element().style.fontFamily);
},
'commands.after': function (cmd, param1, param2) {
// after a command, e.g. the user used the inbuilt font chooser
console.log(this.selection.element().style.fontFamily);
}
}
});
Others might be useful too, from the list at https://froala.com/wysiwyg-editor/docs/events/

Enable / disable Quill on demand

I'm using quill to make myDiv editable like this:
var myQuill = new Quill(myDiv, {
modules: {
toolbar: {
container: myToolbar
}
},
styles: false,
theme: 'snow'
});
I also want Quill to become active or not active (the user cannot edit contents anymore) on demand (e.g. by pressing a button).
Is there something like myQuill.disable() or myQuill.enable()?
I didn't see a Quill command for that, but you could use this to disable it :
$("#DIV_ID .ql-editor").attr('contenteditable', false);
where DIV_ID is your element id chosen when initializing Quill.
For all editors, use the following :
$(".ql-editor").attr('contenteditable', false);
Change false to true to enable back.
Both enable() and disable() exist in Quill 1.0 for this purpose. In Quill 0.20 they are under the editor instance variable so you can do myQuill.editor.enable().

How to detect when a menu is rendered in tinymce 4?

In tinymce 4, the menu bar is rendered but each menu is rendered only on click.
To illustrate this, notice that each menu from the menu bar has the mce-menu class.
At any time, if no menu is open, if you try to get the set of menus, you'll fail because they aren't rendered yet:
var menuSet = $('.mce-menu');
// menuSet.length : 0
But if you click a menu bar header, let say the insert menu, it will be rendered and opened. Now, keeping it open, going to the console and retrying:
var menuSet = $('.mce-menu');
// menuSet.length : 1
and you'll get the opened menu.
Now if you close it clicking anywhere out of the opened menu, and retrying:
var menuSet = $('.mce-menu');
// menuSet.length : 1
... the menu is not removed from the DOM. It's a good news: since the menu was rendered once, we can get and manipulate it.
I have some DOM manipulation to do with each .mce-menu elements, but I'll have to now when each menu is opened the first time.
But how to handle a such event ?
I can't get any clue from the official documentation nor the forums, or anywhere.
It's definitely possible, but we both were not aware enough of how JS events are managed.
I tried to code my events handlers the old way :
$('body').on('click', function() {
do_stuff();
});
While I had to do it the new, correct way :
$('body').on('click', '.mce-btn', function() {
do_stuff();
});
With this, the events are correctly managed.
Try to use onPostrender funtion :
editor.addMenuItem("mybtn", {
type: "menuitem",
name: 'mybtn',
onPostRender:function (){
// write your code here//
},
I resolved the issue by writting a convenient `Tinymce 4 plugin focused on that purpose.
Of course this plugin is open-sourced by the GNU GPL v2 license, following the original Tinymce licensing policy.
Tinymce Plugin MenusController:
https://github.com/sirap-group/tinymce-plugin-menuscontroller
But I didn't wrote the documentation yet, my apologies.
However, here is how you can use it:
Install the plugin
Download the latest release tarball from github or, even better, install it from bower:
bower install tinymce-plugin-menuscontroller
If you don't know bower, discover it here: https://bower.io (npm i -g bower; bower --help).
The npm package isn't available yet, I'd provide it soon (but any Pull Request on github is welcome...).
By default, the plugin folder would be downoaded and placed in ./bower_components. If you've installed tinymce the same way, you've got also ./bower_components/tinymce or ./bower_components/tinymce-dist.
You don't need to add the script to your index.html file because tinymce load it itself if you setup it correctly.
So you need to :
symlink it to the tinymce plugin folder:
$ cd ./bower_components/tinymce/plugins
$ ln -s ../../tinymce-plugin-menuscontroller menuscontroller
load it in tinymce init. For example:
tinymce.init({
selector: 'textarea',
// [...]
plugins: 'menuscontroller'
})
Get the plugin instance:
var editor = window.tinymce.activeEditor
var menusCtl = editor.plugins.menuscontroller
// at this point, if menusCtl is undefined, something gone wrong in the setup step: please check the previous steps.
Plugin API (v0.2.1)
Instance Methods
Get the menu bar:
menusCtl.getMenubar()
Get each menu by the name it was registered with:
menusCtl.getMenuByName(String: name)
Get the toolbars
menusCtl.getToolbars
Events
Event: menusController:mceMenuRendered event
When any tinymce menu is rendered
$('body').on('menusController:mceMenuRendered', function (evt, menuDomNode) {
console.log(menuDomNode)
})
The menusController:mceMenuRendered event is called one for each menu of the active editor menubar, when it is rendered, so when the user click the dropdown menu (File link for the "file" menu, Insert for the "insert" menu, etc...).
Event: menusController:mceMenuItemRendered:<menuDomID>
When any menu item is rendered. Let's say we've created a menu item with the my-custom-menu-item identifier. So tinymce set its DOM ID to my-custom-menu-item. Thus, the MenusController plugin will create and bind to body the following event:
menusController:mceMenuItemRendered:my-custom-menu-item
So you can handle the rendered event of your custom menu item listening on it:
$('body').on('menusController:mceMenuItemRendered:my-custom-menu-item',
function (evt, menuItemDomNode) {
console.log(menuItemDomNode)
}
)
MenusController API (v0.3.0+)
A the time of wrinting (Monday, mars the 13th, 2017), the last released version is the v0.2.1. But the v0.3.0 is planned to be released soon, and will provide a new event, more useful than the last.
Event: menusController:mceMenuItemRendered
When you need to know the menu item ID to handle the event menusController:mceMenuItemRendered:<menuDomID> and get the menu item DOM Node as callback argument, the event menusController:mceMenuItemRendered don't needs it but provides it as callback argument for each new rendered menu item:
$('body').on('menusController:mceMenuItemRendered',
function (evt, menuItemID) {
console.log(menuItemID) // 'my-custom-menu-item'
// So you can hanlde all menu item even if you don't know its ID
// And you can also handle the DOM Node with the selector by ID
var selector = '#' + menuItemID
var menuItem = $(selector)
console.log(menuItem) // jQuery object (the menu item)
}
)
With tinymce you can fully customize the menu buttons via the editor object:
tinymce.init({
/*....*/
setup: function(editor) {
editor.addButton('mybutton', {
type: 'menubutton',
text: 'My button',
icon: false,
onclick: function(){
alert('Some Message');
},
menu: [{
text: 'Menu item 1',
onclick: function() {
alert('Some Message');
}
}]
});
}
/*....*/
});
Unfortunately you cannot insert html inside the text property, but i think you can do that with more research. You can also create a callback function for the click event on the menu button.
Personally, I will use tinymce official api to modify the dom instead of doing some other event driven dom manipulation.
You can find more a good example here

TinyMCE - disable standard save button

I try to disable programmatically the standard "save" button of the save plugin
tinymce.init
({
selector: '#editorMain',
plugins: "save,code,textcolor,charmap,searchreplace,paste,wordcount",
height: 400,
setup: function(editor) {
editor.on('keyup',function(e){
console.log(getStats('editorMain').chars);
var body = tinymce.get('editorMain').getBody();
var currentValue=tinymce.trim(body.innerText || body.textContent);
var currentCharsCount=getStats('editorMain').chars;
var limit=10;
var diff=limit - currentCharsCount;
if (diff>-1)
{
$("#chars_left").html(diff + " characters left");
}
else
{
$("#chars_left").html("Your comment is too long");
// here should we disable the save button
}
});
},
I googled for a solution and found that in version 3.x there was an object called "ControlManager". This has been removed in version 4 (the one I currently use)
According to the documentation the following should be implemented to do that:
// In TinyMCE 4 you can use the simpler stateSelector setting
editor.addButton('SomeButton', {
text: 'My button',
stateSelector: 'a'
});
but how can this work for the "save" button ? the save button comes when I use the "save" plugin, this does not have to be programmatically added.
well that was a tough one. This:
tinymce.activeEditor.theme.panel.find('toolbar *')[1];
enables to access the button. then the ".disabled(1)" method.
That's a pity that we cannot access the elements using their names or ids...
If you don't want the functionality of the save plugin simply remove it from the list in the plugins: init options. Use the list shown here.
tinymce.init
({
selector: '#editorMain',
plugins: "code,textcolor,charmap,searchreplace,paste,wordcount",
....

Get UI button clicked on CK Editor toolbar

I have built a very simple plugin for CK Editor (because apparently that's the only way to add a custom button to the toolbar?)
I'd like to know how I can get the DOM ID of my custom button when it is clicked (or any object representative of the button which will allow me to create a jQuery object)
(function () {
CKEDITOR.plugins.add('myplugin', {
icons: 'myicon',
hidpi: true,
init: function (editor) {
editor.addCommand('mycommand', {
exec : function(editor) {
// get button information
}
});
editor.ui.addButton && editor.ui.addButton('MyCommand', {
label: 'Custom Action',
command: 'mycommand',
toolbar: 'insert,5',
icon: 'myicon'
});
}
});
})();
I'd like to attach my own custom UI element to the toolbar when the button is clicked and I need a relative anchor point in order to display it in the correct position on the screen.
I'm using CK Editor 4.2
In your case, you can access the button with the following code (using jQuery):
$(document).on('click', '.cke_button__mycommand', function(){
// do stuff
});
You can inspect the toolbar with your browser to get more information.

Categories

Resources