Firefox 工具栏按钮上下文(工具栏上的右键单击菜单)

Firefox toolbarbutton context ( right click menu on toolbar )

在 Chrome 中,可以为扩展图标创建上下文菜单项,如下所示:

在 Firefox 中模拟它的最好和最干净的方法是什么 - 最好使用标准工具栏和标准工具栏按钮。

<toolbarpalette id="BrowserToolbarPalette">
    <toolbarbutton class="toolbarbutton-1"
                   label="My button"
                   oncommand="doSomething()" />
</toolbarpalette>

这里有一些小菜一碟的代码,可以满足您的需要:

CustomizableUI.createWidget({
    id: 'noida',
    defaultArea: CustomizableUI.AREA_NAVBAR,
    label: 'My Widget',
    tooltiptext: 'This is my widget created with CUI.jsm',
    onCreated: function(aNode) {
        console.info('aNode:', aNode);
        aNode.setAttribute('image', 'chrome://branding/content/icon16.png');

        var myMenuJson = [
                            'xul:menupopup', {id: 'my_btns_pop'},
                                ['xul:menuitem', {label: 'menu item1'}],
                                ['xul:menu', {label: 'menu item2 is submenu1'},
                                    ['xul:menupopup', {},
                                        ['xul:menuitem', {label: 'submenu1 item1'}],
                                        ['xul:menuitem', {label: 'submenu1 item2'}],
                                        ['xul:menuitem', {label: 'submenu1 item3'}]
                                    ]
                                ],
                                ['xul:menuitem', {label: 'menu item3 is before a seperator'}],
                                ['xul:menuseparator', {}],
                                ['xul:menuitem', {label: 'menu item4 is after a seperator'}]
                        ];
        aNode.appendChild(jsonToDOM(myMenuJson, aNode.ownerDocument, {}));
        aNode.setAttribute('contextmenu', 'my_btns_pop');
    }
});

这里使用 MDN 中的 jsonToDOM 函数:https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/DOM_Building_and_HTML_Insertion#JSON_Templating

如果你想复制粘贴代码和运行到暂存器,复制粘贴这段代码,它有jsonToDom函数复制粘贴在:

function jsonToDOM(json, doc, nodes) {

    var namespaces = {
        html: 'http://www.w3.org/1999/xhtml',
        xul: 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'
    };
    var defaultNamespace = namespaces.html;

    function namespace(name) {
        var m = /^(?:(.*):)?(.*)$/.exec(name);        
        return [namespaces[m[1]], m[2]];
    }

    function tag(name, attr) {
        if (Array.isArray(name)) {
            var frag = doc.createDocumentFragment();
            Array.forEach(arguments, function (arg) {
                if (!Array.isArray(arg[0]))
                    frag.appendChild(tag.apply(null, arg));
                else
                    arg.forEach(function (arg) {
                        frag.appendChild(tag.apply(null, arg));
                    });
            });
            return frag;
        }

        var args = Array.slice(arguments, 2);
        var vals = namespace(name);
        var elem = doc.createElementNS(vals[0] || defaultNamespace, vals[1]);

        for (var key in attr) {
            var val = attr[key];
            if (nodes && key == 'id')
                nodes[val] = elem;

            vals = namespace(key);
            if (typeof val == 'function')
                elem.addEventListener(key.replace(/^on/, ''), val, false);
            else
                elem.setAttributeNS(vals[0] || '', vals[1], val);
        }
        args.forEach(function(e) {
            try {
                elem.appendChild(
                                    Object.prototype.toString.call(e) == '[object Array]'
                                    ?
                                        tag.apply(null, e)
                                    :
                                        e instanceof doc.defaultView.Node
                                        ?
                                            e
                                        :
                                            doc.createTextNode(e)
                                );
            } catch (ex) {
                elem.appendChild(doc.createTextNode(ex));
            }
        });
        return elem;
    }
    return tag.apply(null, json);
}

CustomizableUI.createWidget({
    id: 'noida',
    defaultArea: CustomizableUI.AREA_NAVBAR,
    label: 'My Widget',
    tooltiptext: 'This is my widget created with CUI.jsm',
    onCreated: function(aNode) {
        console.info('aNode:', aNode);
        aNode.setAttribute('image', 'chrome://branding/content/icon16.png');

        var myMenuJson = [
                            'xul:menupopup', {id: 'my_btns_pop'},
                                ['xul:menuitem', {label: 'menu item1'}],
                                ['xul:menu', {label: 'menu item2 is submenu1'},
                                    ['xul:menupopup', {},
                                        ['xul:menuitem', {label: 'submenu1 item1'}],
                                        ['xul:menuitem', {label: 'submenu1 item2'}],
                                        ['xul:menuitem', {label: 'submenu1 item3'}]
                                    ]
                                ],
                                ['xul:menuitem', {label: 'menu item3 is before a seperator'}],
                                ['xul:menuseparator', {}],
                                ['xul:menuitem', {label: 'menu item4 is after a seperator'}]
                        ];
        aNode.appendChild(jsonToDOM(myMenuJson, aNode.ownerDocument, {}));
        aNode.setAttribute('contextmenu', 'my_btns_pop');
    }
});

当然要销毁您的按钮元素,请执行以下代码:

CustomizableUI.destroyWidget('noida');