How to detect when a menu is rendered in tinymce 4?
In tinymce 4
, the menu bar is rendered, but each menu is only rendered when clicked.
To illustrate this, notice that every menu in the menu bar has mce-menu
this class.
At any time, if no menu is open, the attempt to get the menu set fails because the menu has not yet been rendered:
var menuSet = $('.mce-menu');
// menuSet.length : 0
However, if you click on the menu bar title, lets say insert
menu, it will be rendered and opened. Now, keep it open, go to the console and try again:
var menuSet = $('.mce-menu');
// menuSet.length : 1
You will get the menu that opens.
Now, if you close it, click anywhere in the menu that opens and try again:
var menuSet = $('.mce-menu');
// menuSet.length : 1
...the menu is not removed from the DOM. Here's the good news: since the menu is rendered one at a time, we can get and manipulate it.
I need to do some DOM manipulation on each .mce-menu
element , but now it has to be used the first time each menu is opened.
But how to handle such an event?
I can't find any clues from official documentation, forums or anywhere.
I solved this problem by writing a handy `Tinymce 4 plugin that focuses on this purpose.
Of course, this plugin is open sourced under the GNU GPL v2 license following the original Tinymce license policy.
Tinymce plugin menu controller:
https://github.com/sirap-group/tinymce-plugin-menuscontroller
Sorry, I haven't written the documentation yet.
However, here's how to use it:
Install the plugin
Download the latest version tarball from github, or even better install it from bower:
bower install tinymce-plugin-menuscontroller
If you don't know , find itbower
here: https://bower.io ( ) .npm i -g bower; bower --help
The npm package is not available yet, I'll make it available soon (but any Pull Request on github is welcome...).
By default, the location of the plugins folder will be deselected and placed in ./bower_components
. If you installed tinymce the same way, you must also install ./bower_components/tinymce
or ./bower_components/tinymce-dist
.
You don't need to add the script to the file index.html
, because tinymce loads it automatically if you set it up correctly .
Therefore, you need:
Symlink it to the tinymce plugins folder:
$ cd ./bower_components/tinymce/plugins $ ln -s ../../tinymce-plugin-menuscontroller menuscontroller
Load it into tinymce init. E.g:
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 method
Get the menu bar:
menusCtl.getMenubar()
Get each menu by its registered name:
menusCtl.getMenuByName(String: name)
get toolbar
menusCtl.getToolbars
Memorabilia
event: menusController:mceMenuRendered
event
when presenting any tinymce menu
$('body').on('menusController:mceMenuRendered', function (evt, menuDomNode) {
console.log(menuDomNode)
})
menusController:mceMenuRendered
When the event is rendered, each menu of the active editor menu bar refers to the event as an event , so when the user clicks the drop-down menu (File
link for the "File" menu, link for theInsert
"Insert" menu, etc. ) is called an event .
event:menusController:mceMenuItemRendered:<menuDomID>
when any menu item is rendered. Suppose we have created a menu item with an my-custom-menu-item
identifier . So tinymce sets its DOM ID to my-custom-menu-item
. So the MenuController plugin will create and bind the following events to the body:
menusController:mceMenuItemRendered:my-custom-menu-item
So you can handle render events that your custom menu item listens to:
$('body').on('menusController:mceMenuItemRendered:my-custom-menu-item',
function (evt, menuItemDomNode) {
console.log(menuItemDomNode)
}
)
MenusController API(v0.3.0 +)
At the time of this writing (Monday, March 13, 2017), the last released version is
v0.2.1
. But itv0.3.0
is planned to be released soon and will provide a new event that is more useful than the previous one.
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 a callback parameter, the eventmenusController:mceMenuItemRendered
doesn't need it, but instead provides it as a callback parameter for each newly 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)
}
)