本文介绍了取决于所选文本的动态扩展上下文菜单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试根据所选内容在 Chrome 上下文菜单上创建条目.我在 Stackoverflow 上发现了几个与此相关的问题,对于所有问题,答案都是:使用带有mousedown"侦听器的内容脚本,该侦听器查看当前选择并创建上下文菜单.

I am trying to create entries on the Chrome context menu based on what is selected.I found several questions about this on Stackoverflow, and for all of them the answer is: use a content script with a "mousedown" listener that looks at the current selection and creates the Context Menu.

我实现了这个,但它并不总是有效.有时所有的日志消息都说上下文菜单按照我的意愿进行了修改,但出现的上下文菜单没有更新.

I implemented this, but it does not always work. Sometimes all the log messages say that the context menu was modified as I wanted, but the context menu that appears is not updated.

基于此,我怀疑这是一个竞争条件:有时 chrome 在代码完全运行之前就开始呈现上下文菜单.

Based on this I suspected it was a race condition: sometimes chrome starts rendering the context menu before the code ran completely.

我尝试将 eventListener 添加到contextmenu"和mouseup".当用户用鼠标选择文本时,后者会触发,因此它会在上下文菜单出现之前(甚至几秒钟)改变它.即使使用这种技术,我仍然看到同样的错误发生!

I tried adding a eventListener to "contextmenu" and "mouseup". The later triggers when the user selects the text with the mouse, so it changes the contextmenu much before it appears (even seconds). Even with this technique, I still see the same error happening!

这种情况在 Chrome 22.0.1229.94 (Mac) 中经常发生,偶尔在 Chromium 20.0.1132.47 (linux) 中发生,并且在 Windows (Chrome 22.0.1229.94) 上尝试 2 分钟后没有发生.

This happens very often in Chrome 22.0.1229.94 (Mac), occasionally in Chromium 20.0.1132.47 (linux) and it did not happen in 2 minutes trying on Windows (Chrome 22.0.1229.94).

究竟发生了什么?我该如何解决?还有其他解决方法吗?

What is happening exactly? How can I fix that? Is there any other workaround?

这是我的代码的简化版本(不是那么简单,因为我保留了日志消息):

Here is a simplified version of my code (not so simple because I am keeping the log messages):

{
  "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);

背景.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({});
});

推荐答案

contextMenus API 用于定义上下文菜单条目.不需要在打开上下文菜单之前立即调用它.因此,不要在上下文菜单事件上创建条目,而是使用 selectionchange 事件来不断更新上下文菜单条目.

The contextMenus API is used to define context menu entries. It does not need to be called right before a context menu is opened. So, instead of creating the entries on the contextmenu event, use the selectionchange event to continuously update the contextmenu entry.

我将展示一个简单的例子,它只在上下文菜单条目中显示所选文本,以表明条目同步良好.

I will show a simple example which just displays the selected text in the context menu entry, to show that the entries are synchronized well.

使用此内容脚本:

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

在后台,我们将只创建一次上下文菜单条目.之后,我们更新上下文菜单项(使用我们从 chrome.contextMenus.create).
如果选择为空时,我们会在需要时删除上下文菜单条目.

At the background, we're going to create the contextmenu entry only once. After that, we update the contextmenu item (using the ID which we get from chrome.contextMenus.create).
When the selection is empty, we remove the context menu entry if needed.

// 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.

To keep this example simple, I assumed that there's only one context menu entry. If you want to support more entries, create an array or hash to store the IDs.

  • 优化 - 为了减少 chrome.contextMenus API 调用的次数,缓存参数的相关值.然后,使用简单的=== 比较来检查是否需要创建/更新 contextMenu 项.
  • 调试 - 所有 chrome.contextMenus 方法都是异步的.要调试代码,请将回调函数传递给 .create.remove.update 方法.
  • Optimization - To reduce the number of chrome.contextMenus API calls, cache the relevant values of the parameters. Then, use a simple === comparison to check whether the contextMenu item need to be created/updated.
  • Debugging - All chrome.contextMenus methods are asynchronous. To debug your code, pass a callback function to the .create, .remove or .update methods.

这篇关于取决于所选文本的动态扩展上下文菜单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 18:47