Uniquely identify image elements with browser.contextMenus.onClicked.addListener()

I’m trying to uniquely identify images that I click with a contextMenu, however I’m trying to resolve the edge case where there are multiple images with the same src.

Looking at the values in contextMenus.OnClickData there seems to be a targetElementId and parentMenuItemId which could be useful. However, when trying to use contextMenus.getTargetElement() in my content script to retrieve the targeted element (as described in the documentation) I’m getting the following error:

Uncaught (in promise) Error: browser.contextMenus is undefined

My question is why is browser.contextMenus not available in my content script? Also, I’m confused what the parentMenuItemId can be used for? Can it be accessed like with contextMenus.getTargetElement()? The documentation is not very descriptive of this value.

manifest.json

{
  "manifest_version": 2,
  ...
  "permissions": [
    "activeTab",
    "storage",
    "tabs",
    "contextMenus"
  ],
  "content_scripts": [
    {
      "matches": [
        "*://*/*"
      ],
      "js": [
        "content_script.js"
      ],
      "run_at": "document_idle"
    }
  ],
  "background": {
    "scripts": [
      "background.js"
    ],
    "persistent": false
  }
...
}

background.js

// ===== initialize context menu for single image adjustment on right click
browser.contextMenus.create(
  {
    id: "adjust-single-image",
    title: "Adjust Single Image",
    contexts: ["image"]
  }
)

browser.contextMenus.onClicked.addListener((info, tab) => {
  console.log(info)
  browser.tabs.sendMessage(tab.id, { 
    action: 'adjustSingleImage', 
    imageInfo: {
      parentMenuItemId: info.parentMenuItemId,
      targetElementId: info.targetElementId,
      srcUrl: info.srcUrl,
      frameId: info.frameId
    }
  })
})

content_script.js

// ===== listen for message from popup or background script to apply changes
browser.runtime.onMessage.addListener(async (request) => {
    console.log("got msg: " + request.action)
    if ('action' in request && (request.action === 'enableFilter' || request.action === 'enableImageFilter' || request.action === 'changeType')) {
        location.reload()
    } else if (request.action === "adjustSingleImage") {
        let {srcUrl, targetElementId, parentMenuItemId, frameId} = request.imageInfo;
        let image;
        if (targetElementId) {
            console.log("Found targetElementId")
            image = browser.contextMenus.getTargetElement(targetElementId);
        // can this be done?
        //} else if (parentMenuItemId && srcUrl) {
        //    console.log("Found parentMenuItemId")
        //    let parent = browser.contextMenus.getTargetElement(parentMenuItemId);
        //    image = parent.querySelector(`img[src="${srcUrl}"]`)
        } else if (srcUrl) {
            console.log("Found srcUrl")
            image = document.querySelectorAll(`img[src="${srcUrl}"]`)[0]
        } else {
            console.log("Error: could not find selected image");
            return
        }

        console.log(image);
    }
});

It is some time ago I read the documentation. But if like when I read it, it several times sounds like browser.contextMenus and browser.menus are just aliases. They are not. browser.menus are a superset of browser.contextMenus, the difference being that targetElementId and getTargetElement() are only available in the browser.menus namespace.
EDIT: Or maybe more precise… Only browser.menus are available in content scripts. targetElementId might be available in both namespaces(???), but you need to use menus namespace to access getTargetElement() in content scripts.

So making the switch to menus instead of contextMenus will definitely be the first step to do.

I have never looked at or used parentMenuItemId myself, but could be related to when creating submenus in the contextmenu?

Thanks for the reply! I changes the namespace in all my files to menus and it’s working fine now.

The reason why I wanted to use contextMenus is because I plan on porting my extension to Chrome and Safari in the future. Since getTargetElement is only available for contextMenus, I’m still stuck with the issue of uniquely identifying images with the same srcUrl. For now it works, but I’m going to keep doing research on how to best solve this problem.

Found this Stack Overflow post which recommends using a listener in the content script for the “contextmenu” event and then retrieves the event target. I will probably go with this solution in the future.