I am trying to rewrite a chrome extension from manifest version 2 to manifest version 3.
What the extension does is use selected text to create a specific URL. It adds an item to the contextMenu in Chrome browser based on the selected text and when the user clicks that item, the URL is opened in a new window.
I use a content_script with a document event listener to send a message to the backgroundscript, every time the selected text changes (which is very often when you are selecting text).
So this is my content_script.js. I did not change anything here for going from manifest 2 to 3.
//Add event listener: checks for selectionchanges by user
document.addEventListener('selectionchange', function() {
var selection = window.getSelection().toString().trim();
chrome.runtime.sendMessage({
request: 'updateContextMenu',
selection: selection
});
});
In my background script, I add a listener for these messages. This checks if the menu item exists. If it exists it updates the item, if not, it creates the item.
In manifest version 2, I did it like this:
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 {
var options = {
title: "Open '%s' in Service-Now",
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);
}
}
}
});
But going to manifest version 3, I needed to change some things. I got an error on the onclick property, so I changed that to an event listener. (And I can't call window.open from a service_worker apparently, so I will have to change that as well, but that is not what my question is about.)
chrome.contextMenus.onClicked.addListener(function(clickData, tab) {
var sn_url = get_servicenow_url(clickData.selectionText);
console.log("debug: open URL " + sn_url);
Clients.openWindow(sn_url, '_blank');
//window.open(sn_url, '_blank');
});
Next to that, I had en error:
Error in event handler: TypeError: Error in invocation of contextMenus.update([integer|string] id, object updateProperties, optional function callback): Error at parameter 'updateProperties': Unexpected property: 'id'. at chrome-extension://adpocbbofaopmokkheddloekfodplnnk/background.js:117:37
According to the chrome documentation contextMenus.update should accept the same parameters als contextMenus.create. But then it does not because this is what the documentation states for contextMenu.update. Note ID is mentioned seperately.
PARAMETERS id (string | number) - The ID of the item to update.
updateProperties (object) - The properties to update. Accepts the same values as the contextMenus.create function.
Where for contextMenus.create id is defined as one of the possible createProperties
createProperties (object) id (string optional) - The unique ID to assign to this item. Mandatory for event pages. Cannot be the same as another ID for this extension.
I cannot leave the ID because create needs it and I cannot put the id in my array, because for update it needs to be the seperate first thing in the command.
https://developer.chrome.com/docs/extensions/reference/contextMenus/#method-update\
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
} // else: No contextmenu ID, so nothing to remove
} else {
var options = {
id: "OpenSnow", //mandatory for createMenu
title: "Open '%s' in Service-Now",
contexts: ["selection"]
};
if (cmid != null) {
chrome.contextMenus.update(options);
} else {
// Create new menu, and remember the ID
cmid = chrome.contextMenus.create(options);
console.log("debug: first time creation" + );
}
}
}
});
I get the following error when I try to run this codeblock:
Error in event handler: TypeError: Error in invocation of contextMenus.update([integer|string] id, object updateProperties, optional function callback): No matching signature. at chrome-extension://adpocbbofaopmokkheddloekfodplnnk/background.js:110:37
Which is this line of code:
chrome.contextMenus.update(options);
But changing that line to call the id:
chrome.contextMenus.update(cmid, options);
or
chrome.contextMenus.update(id: "OpenSnow", options);
Both give me different errors again.
If someone can help me identify the error in my code for Manifest version 3, that would be really helpful. Or if there is a better way of doing this overall where there are not so many messages send while updating the selected text, that would work as well, I am open to suggestions.
It turned out to be way easier than my previous solution. I don't need the content script anymore. In the service_worker I create a menu item, using %s to show the selected text, that only shows when there is a selection and is created once when the extension is installed.
Then I create a listener for when the context menu item is clicked and there the necessary code is run.
//define contextMenuItem
var contextMenuItem = {
"id": "OpenSN",
"title": "Open %s in ServiceNow",
"contexts": ["selection"]
};
//on installation of chrome extension: create contextMenuItem
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
id: "OpenSN",
title: "Open %s in Service-Now",
contexts: ["selection"]
});
});
//add listener for click on self defined menu item
chrome.contextMenus.onClicked.addListener(function(clickData){
if (clickData.menuItemId == "OpenSN" && clickData.selectionText) {
//run code here
}
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With