在Chrome扩展动态创建上下文菜单失败(Creating dynamic context menu

2019-06-18 19:46发布

我试图创建一个基于所选内容的Chrome浏览器右键菜单项。 我发现这个几个问题#2,和所有的人的答案是:使用内容脚本以“鼠标按下”监听器,着眼于当前的选择,并创建上下文菜单。

我实现了这一点,但它并不总是工作。 有时候,所有日志消息说,上下文菜单被修改,因为我想,但没有更新出现的上下文菜单。

在此基础上我怀疑这是一个竞争条件:有时启动Chrome渲染上下文菜单之前的代码完全跑了。

我尝试添加一个事件监听到“文本菜单”和“鼠标松开”。 当用户选择与鼠标的文字,因此它改变多之前它出现(甚至几秒钟)的文本菜单的后面的触发器。 即使有这样的技术,我仍然看到了同样的错误发生!

这种情况往往在Chrome 22.0.1229.94(苹果机),偶见于铬20.0.1132.47(Linux版),并没有在2分钟内试图在Windows器(Chrome 22.0.1229.94)发生。

这是怎么回事到底是什么? 我该如何解决呢? 还有没有其他的解决方法吗?


这里是我的代码的简化版本(并非如此简单,因为我保持的日志消息):

manifest.json的:

{
  "name": "Test",
  "version": "0.1",
  "permissions": ["contextMenus"],
  "content_scripts": [{
    "matches": ["http://*/*", "https://*/*"],
    "js": ["content_script.js"]
  }],
  "background": {
    "scripts": ["background.js"]
  },
  "manifest_version": 2
}

content_script.js

function loadContextMenu() {
  var selection = window.getSelection().toString().trim();
  chrome.extension.sendMessage({request: 'loadContextMenu', selection: selection}, function (response) {
    console.log('sendMessage callback');
  });
}

document.addEventListener('mousedown', function(event){
  if (event.button == 2) {
    loadContextMenu();
  }
}, true);

background.js

function SelectionType(str) {
  if (str.match("^[0-9]+$"))
    return "number";
  else if (str.match("^[a-z]+$"))
    return "lowercase string";
  else
    return "other";
}

chrome.extension.onMessage.addListener(function(msg, sender, sendResponse) {
  console.log("msg.request = " + msg.request);
  if (msg.request == "loadContextMenu") {
    var type = SelectionType(msg.selection);
    console.log("selection = " + msg.selection + ", type = " + type);
    if (type == "number" || type == "lowercase string") {
      console.log("Creating context menu with title = " + type);
      chrome.contextMenus.removeAll(function() {
        console.log("contextMenus.removeAll callback");
        chrome.contextMenus.create(
            {"title": type,
             "contexts": ["selection"],
             "onclick": function(info, tab) {alert(1);}},
            function() {
                console.log("ContextMenu.create callback! Error? " + chrome.extension.lastError);});
      });
    } else {
      console.log("Removing context menu")
      chrome.contextMenus.removeAll(function() {
          console.log("contextMenus.removeAll callback");
      });
    }
    console.log("handling message 'loadContextMenu' done.");
  }
  sendResponse({});
});

Answer 1:

contextMenus API是用来定义上下文菜单项。 它不需要被称为上下文菜单打开右侧前。 所以,与其在contextmenu事件创建条目,请使用selectionchange事件不断更新文本菜单项。

我将展示这只是显示在上下文菜单项选中的文本,表明该条目同步以及一个简单的例子。

使用此内容脚本:

document.addEventListener('selectionchange', function() {
    var selection = window.getSelection().toString().trim();
    chrome.runtime.sendMessage({
        request: 'updateContextMenu',
        selection: selection
    });
});

在后台,我们将只有一次创建文本菜单项。 在那之后,我们更新了文本菜单项(使用我们从拿到ID chrome.contextMenus.create )。
当选择是空的,我们如果需要删除上下文菜单项。

// ID to manage the context menu entry
var cmid;
var cm_clickHandler = function(clickData, tab) {
    alert('Selected ' + clickData.selectionText + ' in ' + tab.url);
};

chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
    if (msg.request === 'updateContextMenu') {
        var type = msg.selection;
        if (type == '') {
            // Remove the context menu entry
            if (cmid != null) {
                chrome.contextMenus.remove(cmid);
                cmid = null; // Invalidate entry now to avoid race conditions
            } // else: No contextmenu ID, so nothing to remove
        } else { // Add/update context menu entry
            var options = {
                title: type,
                contexts: ['selection'],
                onclick: cm_clickHandler
            };
            if (cmid != null) {
                chrome.contextMenus.update(cmid, options);
            } else {
                // Create new menu, and remember the ID
                cmid = chrome.contextMenus.create(options);
            }
        }
    }
});

为了保持这个例子简单,我认为只有一个上下文菜单项。 如果你想支持多个条目,创建一个数组或哈希存储的ID。

提示

  • 优化 -减少的数量chrome.contextMenus API调用,缓存参数的相关数值。 然后,使用一个简单的===比较来检查文本菜单项目是否需要创建/更新。
  • 调试 -所有chrome.contextMenus方法是异步的。 要调试代码,传递一个回调函数来.create.remove.update方法。


文章来源: Creating dynamic context menu in Chrome Extension is failing