javascriptextjsevent-handlingdom-eventsextjs5

Right click context menu with Ext.form.field.HtmlEditor


Problem description

I have prepared this index.html, which creates a simple Ext.form.field.HtmlEditor. I want to have a right-click-context-menu, which is capable of doing something with words that were marked by the user:

<!DOCTYPE html>
<html>
<head>        
    <script type="text/javascript" src="/ext-5.1.1/build/ext-all-debug.js"></script>

    <link id="theme1" rel="stylesheet" type="text/css" href="/ext-5.1.1/build/packages/ext-theme-neptune/build/resources/ext-theme-neptune-all.css">
    <script type="text/javascript" src="/ext-5.1.1/build/packages/ext-theme-neptune/build/ext-theme-neptune.js"></script>

    <script type ="text/javascript">
    Ext.onReady( function(){

        var html_editor = Ext.create('Ext.form.HtmlEditor', {
                renderTo: Ext.getBody()
            });
        });


    </script>
</head>
<body></body>

What i have done so far:

I have tried to implement listeners and a contextmenu, but it doesnt show the menu when right-clicking, so at the end of the day my index.html looked like:

<!DOCTYPE html>
<html>
<head>        
    <script type="text/javascript" src="/ext-5.1.1/build/ext-all-debug.js"></script>

    <link id="theme1" rel="stylesheet" type="text/css" href="/ext-5.1.1/build/packages/ext-theme-neptune/build/resources/ext-theme-neptune-all.css">
    <script type="text/javascript" src="/ext-5.1.1/build/packages/ext-theme-neptune/build/ext-theme-neptune.js"></script>

    <script type ="text/javascript">
    Ext.onReady( function(){

        var html_editor_right_click_menu_action_1 = Ext.create('Ext.Action', {
            text: 'html_editor_right_click_menu_action_1',
            handler: function(widget, event) {
                console.log("html_editor_right_click_menu_action_1 clicked!");
            }
        });
        var html_editor_right_click_menu = Ext.create('Ext.menu.Menu', {
            items: [html_editor_right_click_menu_action_1]
        });


        var html_editor = Ext.create('Ext.form.HtmlEditor', {
                renderTo: Ext.getBody(),
                viewConfig: {
                    listeners: {
                        containercontextmenu: function(view, e, eOpts) {
                            console.log("containercontextmenu listener");
                        }
                    }
                }
            });
        });


    </script>
</head>
<body></body>

Unfortunately, neither a console.log() for the right-click nor a right-click-menu is showing up. Can someone point me in the right direction?

EDIT: (progress made)

I made a context menu appear using this code in index.html (the index.html is runnable for itself, if someone wants to copy&paste it), but i can't get rid of the browsers-context-menu showing inside the html_editor:

<!DOCTYPE html>
<html>
<head>        
    <script type="text/javascript" src="/ext-5.1.1/build/ext-all-debug.js"></script>

    <link id="theme1" rel="stylesheet" type="text/css" href="/ext-5.1.1/build/packages/ext-theme-neptune/build/resources/ext-theme-neptune-all.css">
    <script type="text/javascript" src="/ext-5.1.1/build/packages/ext-theme-neptune/build/ext-theme-neptune.js"></script>

    <script type ="text/javascript">
    Ext.onReady( function(){

        var html_editor_right_click_menu_action_1 = Ext.create('Ext.Action', {
            text: 'html_editor_right_click_menu_action_1',
            handler: function(widget, event) {
                console.log("html_editor_right_click_menu_action_1 clicked!");
            }
        });
        var html_editor_right_click_menu = Ext.create('Ext.menu.Menu', {
            items: [html_editor_right_click_menu_action_1]
        });


        var html_editor = Ext.create('Ext.form.HtmlEditor', {
                renderTo: Ext.getBody()                 
            });

        html_editor.getEl().addListener('click', 
                                    html_editor_click_handler, 
                                    html_editor);
        function html_editor_click_handler(btn, e, eOpts){
            var clicked_button = btn.button;
            var click_x_pos = btn.pageX;
            var click_y_pos = btn.pageY;
            console.log(clicked_button + " " + click_x_pos + " " + click_y_pos);
            if(clicked_button == 2){
                html_editor_right_click_menu.showAt(click_x_pos,click_y_pos);
            }
        }

        });
    </script>
</head>
<body></body>

How to stop the browser-context-menu from appearing above the extjs5-context-menu?


Solution

  • To prevent the default context menu from showing up, call event.preventDefault()

    However, there is an extra wrinkle in this case. The HTMLEditor creates an iframe which is used to do the editing.

    You have to then set a contextmenu listener on the body of the iframe, after it has loaded. See https://fiddle.sencha.com/#fiddle/ncn

    You should not do what you were doing (handling the click and checking which button was clicked) because there are other ways to show the context menu. On the Mac, you can ctrl+click, on Windows you can use the context menu key on the keyboard.

    var html_editor_right_click_menu_action_1 = Ext.create('Ext.Action', {
        text: 'html_editor_right_click_menu_action_1',
        handler: function(widget, event) {
            console.log("html_editor_right_click_menu_action_1 clicked!");
        }
    });
    
    var html_editor_right_click_menu = Ext.create('Ext.menu.Menu', {
        items: [html_editor_right_click_menu_action_1]
    });
    
    var html_editor = Ext.create('Ext.form.HtmlEditor', {
        renderTo: Ext.getBody()
    });
    
    // Find the iframe and wait until it's loaded
    var iframe = html_editor.getEl().down('iframe', true);
    iframe.addEventListener('load', function() {
        // It's loaded, now set the context menu listener
        var body = iframe.contentWindow.document.body;
        body.addEventListener('contextmenu', html_editor_click_handler);
    });
    
    function html_editor_click_handler(e, iframe) {
        // Prevents the default context menu
        e.preventDefault();
        var click_x_pos = e.pageX;
        var click_y_pos = e.pageY;
        console.log("Context click " + click_x_pos + " " + click_y_pos);
        html_editor_right_click_menu.showAt(click_x_pos, click_y_pos);
    
    }