Detect Ext.menu.Menu close/ outfocus - javascript

May i know how to detect when Ext.menu.Menu is closed / outfocus.
i would like to have some action done when the menu closed or outfocused.
Ext.create( 'Ext.menu.Menu',
{ width : 100
, margin : '0 0 10 0'
, floating : false
, renderTo : Ext.getBody()
, items :
[ { text : 'regular item 1' }
, { text : 'regular item 2' }
, { text : 'regular item 3' }
]
}
);

You can use listeners to execute some logic when a supported event occurs. For example to detect if the menu was hidden (like a context menu dismissed) you can use the hide listener.
Add this to the Ext.create config of your menu:
listeners: {
hide: function (sender, eOpts) {
console.log('menu hide listener invoked');
}
}
For a complete list of available listeners on Ext.menu.Menu, check the documentation for the classic and for the modern framework.

You can also check "Collapse" config which accepts boolean value.
Also, on Collapse you can write your logic
listeners: {
collapse: function(panel, eOpts) {
console.log('panel', panel.getCollapsed());
}
}

Related

TinyMCE 5.x - Highlight an item in a custom dropdown menu

I have 3 menu items in a custom TinyMCE 5.x dropdown that controls the width of the editor. I want to indicate what the current selection is, but can't find a way to interact with the menu items after they are initialized. When the menu is closed they don't seem to be in the DOM at all.
I would be happy if my custom dropdown behaved like the font-size dropdown, which displays a check mark next to the selected size. I would also be happy with it being like the font-family dropdown where the selected font is displayed as the menu toggle (not just when you open the menu).
editor.ui.registry.addMenuButton('maxWidth', {
text: 'Width',
fetch: function( callback ){
var items = [
{
type: 'menuitem',
text: 'Full Width',
onAction: function(){ changeSectionWidth("full"); }
},
{
type: 'menuitem',
text: '1600',
onAction: function(){ changeSectionWidth(1600); }
},
{
type: 'menuitem',
text: '1170',
onAction: function(){ changeSectionWidth(1170); }
},
];
callback(items);
},
});
After looking all over and finding nothing useful, I hacked it together, which I am not happy about, but it does work:
//LOCATE THE BUTTON GROUP (happens to be in group 12, starts on 0 though)
let btnGroup = $(editor.editorContainer).find(".tox-toolbar__group")[11];
if( btnGroup ){
return false;
}
//GET THE SPECIFIC BUTTON IN THAT GROUP (happens to be in slot 4, starts on 0)
let targetBTN = $(btnGroup).children()[3];
//CLICK HANDLER FOR THE SPECIFIC MENUBUTTON
$(targetBTN).on("click", function(){
//USE A TIMER SO TinyMCE HAS TIME TO RENDER THE MENU
window.setTimeout( function(){
//APPLY YOUR OWN LOGIC HERE TO DETERMINE WHICH OPTION TO SELECT
//this has to match the words in the button and is case-sensitive
let selectedOption = "Option 2";
//DESELECT OTHER OPTIONS
//NOTE THAT I AM USING AN EXTRA CLASS "my-selected" WHICH I APPLIED TO THE UI SKIN.min.css BECAUSE HOVER DESELECTED THEIR HIGHLIGHTS AND I WANTED IT MORE PERMANENT
$(".tox-selected-menu .tox-collection__item--active").removeClass("tox-collection__item--active tox-collection__item--enabled my-selected");
$('.tox-collection__item[title="'+selectedOption+'"]').addClass("tox-collection__item--active tox-collection__item--enabled my-selected");
}, 50); //WAIT 50 milliseconds so menu has time to be rendered
});
Edit: I know this is old, but might help others.
This can be done using formats and hooking into onSetup on each menu item. See below working example.
editor.ui.registry.addMenuButton('maxWidth', {
text: 'Width',
fetch: callback => {
// Define out options for width.
var widthOptions = [
{
title: 'Full width',
format: 'full_width',
},
{
title: 'Width 2',
format: 'width2',
},
{
title: 'Width 3',
format: 'width3',
},
];
var items = [];
// Add each option to menu items.
widthOptions.forEach(option => {
// Register a custom format for each option.
// See https://www.tiny.cloud/docs/configure/content-formatting/#formats
editor.formatter.register(option.format, {
inline: 'span',
classes: option.format,
});
items.push({
type: 'togglemenuitem',
text: option.title,
onAction: action => {
// We only allow one to be selected. Remove all but the one we clicked.
widthOptions.forEach(opt => {
if (
option.format !=
opt.format
) {
tinymce.activeEditor.formatter.remove(
opt.format,
);
}
});
// Now toggle the selected one.
editor.execCommand(
'FormatBlock',
false,
option.format,
);
},
onSetup: function(api) {
// When generating the item, check if this one is selected.
if (
editor.formatter.match(
option.format,
)
) {
api.setActive(true);
}
return function() {};
},
});
});
callback(items);
},
});

How can I add a dynamic context menu to tinyMCE?

Is there a way to add custom dynamic elements to the context menu in tinyMCE 4.x, after init? I created custom menu items but many of them have sub-items that are dependent on other things going on in my application.
I tried using editor.on('contextmenu') but the menu still does not update. Any ideas?
Add the contextmenu plugin
Override the default context menu (some plugins automatically add their own entries) by defining the contextmenu option. It is a pipe-delimited list of custom menu items (which you define in step 3)
Define a list of custom menu items. These can have their own onclick event handlers, or define sub-menus.
tinymce.init({
...
plugins: [..., 'contextmenu'],
contextmenu: 'customItem1 | customItem2',
setup: function (editor) {
editor.addMenuItem('customItem1', {
text: 'Menu Item 1',
context: 'tools',
onclick: function () {
alert('Menu item 1 clicked');
}
});
editor.addMenuItem('customItem2', {
text: 'Menu Item 2',
context: 'tools',
menu: [ {
text: "Sub-menu item 1",
onclick: function () {
alert('Sub-menu item 1');
}
}, {
text: "Sub-menu item 2",
onclick: function () {
alert('Sub-menu item 2');
}
}]
});
}
});
References:
TinyMCE addMenuItem
TinyMCE contextmenu plugin doc
Custom menu item blog post
Similar SO question
Yes, it is possible.
The JavaScript Object Function can be used to declare a value dynamically inside editor events.
Even you can go for loops, but only one menu is supported in Dynamic (Since Context Menu Value is unique) make dummy context menu and declare separately (Apply your own logic).
On Sub-menu: to create a Dynamic Menu, use an Array and push it via JavaScript Object Methods in loops to display dynamically.
For Reference : Dynamic data added in custom TinyMCE Editor using AngularJs
This is how I did it
I used jQuery $.each to iterate through my objects, you could also use vanilla JavaScript
//register plugin to process context menu on a specific tag
tinymce.PluginManager.add('contextmenu-plugin', function (editor) {
var selectedCode
// Create a function which returns an array of items, these can be Submenus or Simple Items
var contextMenuItems = () => {
return [
{
type: 'submenu',
text: "Submenu 1",
getSubmenuItems: () => {
if (selectedCode){
var contextMenuItems = []
$.each( ArrayWithData, (index, data ) => {
contextMenuItems.push({
type: 'item',
text: `${data}`,
onAction: () => {
console.log("Clicked submenu option");
}
})
})
// return array of contextmenuitems -> this goes to the Submenu
return contextMenuItems
}
}
},
{
icon: 'remove',
text: 'Remove data',
onAction: () => {
console.log(`Removed data`)
}
}
}
]
}
// now register the contextmenu
editor.ui.registry.addContextMenu('contextmenu', {
update: function (element) {
//this way you can call contextMenuItems() every time you show the context menu
return (element.tagName == "your-condition" && element.className.includes("another condition") ) ? contextMenuItems() : ""
}
});
});

How come my ExtJS 5 panel cannot resolve a show listener via it's VC? W/ Fiddle

ExtJS 5.1.3 - I'm slightly baffled that a simple Panel cannot resolve its VC on 'show' event. The attached fiddle will work - it has a panel with VC. Click the button to see the VC correctly resolved.
If you un-comment the 'show' event however, the code will fail in the console because the function can't be found (Unable to dynamically resolve scope for "show" listener on mypanel-xxxx). Lots of my code works like this already, am I doing something stupid?
I've tried using add() instead of widget() in case it's some kind of MVC nesting issue but Ext just seeks the function in the wrong VC - the top-level VC applied to the viewport.
Any help very much appreciated. Thx
https://fiddle.sencha.com/#view/editor&fiddle/1kvd
Ext.define('Admin.view.TheController', {
extend : 'Ext.app.ViewController',
alias : 'controller.thecontroller',
doShowStuff : function() {
Ext.Msg.alert('SHOW STUFF!', 'yep, this works');
},
doOkStuff : function() {
Ext.Msg.alert('OK STUFF!', 'yep, this works');
}
});
Ext.define('Admin.view.Panel.MyPanel', {
extend : 'Ext.panel.Panel',
alias : 'widget.mypanel',
autoRender : true,
autoShow : true,
controller : 'thecontroller',
width : 200,
height : 200,
html : 'I am your panel',
buttons : [
{ text : 'OK', handler : 'doOkStuff', scope : 'controller' }
],
listeners : [
// This listener causes an error
//{ show : 'doShowStuff', scope : 'controller' },
]
});
Ext.widget('mypanel');
listeners: {
// This listener causes an error
show:{
fn: 'doShowStuff',
scope: 'controller'
}
}
here's the fiddle
Your listeners are misconfigured, they should be an object, not an array. Also, you should omit the scope, it will be automatically determined:
Ext.define('Admin.view.Panel.MyPanel', {
extend: 'Ext.panel.Panel',
alias: 'widget.mypanel',
autoShow: true,
controller: 'thecontroller',
width: 200,
height: 200,
html: 'I am your panel',
buttons: [{
text: 'OK',
handler: 'doOkStuff'
}],
listeners: {
show: 'doShowStuff'
}
});

SenchaTouch 2 : Same toolbar used across the views is firing the same event multiple times

BackGround:
I am using the same toolbar in all my views which is defined in a separate view. This toolbar has four buttons. Since this button has 'id' attribute,
tap event on one button from a view will trigger similar tap events from other views as well since the same toolbar is used across the views.
My Toolbar is as below.
Ext.define("WU.view.WUToolBar", {
extend: "Ext.Toolbar",
alias: "widget.wuToolBar",
xtype:"wuToolBar",
config: {
docked : 'bottom',
cls : 'tabBar',
ui:'widgetBottombarUI',
items : [
{
xtype : 'button',
text : 'My Account',
cls : 'profileTabBar',
id : 'myProfileButton',
listeners : {
tap : function(button, e, eOpts) {
console.log('myProfileButton is clicked');
}
},
{
xtype : 'button',
text : 'Help',
cls : 'helpTabBar',
id : 'helpTabButton',
listeners : {
tap : function(button, e, eOpts) {
console.log('helpButton is clicked');
}
},
]
},
});
I am adding this to my different views in the items config as below.
xtype : 'wuToolBar'
So, tap event on a button in a single view will fires the tap event from all the views since this toolbar is shared across the pages. If I am removing the
id attribute then application works fine but I need to assign the id to the button since I have to access them using getCmp method.
If it is on all views, then I would suggest adding it in your app.js, and then simply add to the Viewport when you move from screen to screen:
In app.js:
...
launch: function() {
...
// Add static components
Ext.Viewport.add([
{
xtype: 'wuToolBar'
docked: 'bottom' // I would recommend moving this out of your customized config
}
]);
...
},
...
You can add a view later using the same method (Ext.Viewport.add(...)), or you can use the Ext.navigation.View component.

TreeNode click event on ExtJs 4

I'm using ExtJS 4 (beta 3) and I have a TreePanel that is my kind of navigation menu.
It is something like this:
Jobs
Add Job
List All Jobs
...
...
...
(this will be made on a permission system base, but that's another story)
On ExtJS 3, do something when i clicked "Add Job" was as simple as adding
...
leaf:true,
listeners:{
click:function(n){
//my code...
}
}
...
to the root children elements.
Now It's not that simple. The closer i got was with (on the treepanel)
listeners:{
click : {
element : 'el',
fn : function(eve, elem, obj){
console.log(node);
console.log(elem);
console.log(obj);
}
}
}
So, maybe i'm just a noob, maybe i have already a strong hatred for ExtJS, maybe is just a problem in this beta version, but...
How do I add a listener to the click event on the tree nodes? (the Select event won't do what i need)
Thank you guys.
EDIT: Currently testing with this, and it's not working.
... = Ext.create('Ext.tree.TreePanel', {
region : 'west',
collapsible : false,
title : 'ITMI',
width : 220,
margins : '5 5 5 5',
cmargins : '5 5 5 5',
hideHeaders : true,
useArrows : true,
rootVisible : false,
headers: [{
xtype : 'treeheader',
text : 'Nome',
flex : 1,
dataIndex: 'nome'
}],
store: store,
listeners:{
itemclick: function(n){
console.info(n);
}
}
...
EDIT 2: The itemclick event now works (on EXJS 4 final), It still doesn't solve my problem. I'd Like to call a specific function when i call each treenode. Before it was really easy. Now i can't figure it out.
in ext4 beta3 (maybe in final release too)... there is no longer click event....
this has changed to itemclick more info
var tree = Ext.create('Ext.tree.Panel', {
store: store,
renderTo: Ext.getBody(),
height: 300,
width: 250,
title: 'Files',
listeners:{
itemclick: function(n){
console.info(n);
}
}
});
So, It may help some people who may be struggling with the same issue I did then.
The "itemclick" event is the way to handle leafs clicks, and it didn't work then for reasons I don't remember.
I accomplished what I needed by splitting the config I had in the database, something like
controllerName|functionName
and then call this code on the handler of the "itemclick:
this.getController(ctr)[fn]();
where ctr is the controllerName and fn is the functionName. This could easily be done with eval, but I prefer not to.
I could not get itemclick to fire with IE (fine in Chrome). I modified my code to use 'checkchange' and it works fine.

Categories