Why not brush up the contextMenu API a little?

177 views
Skip to first unread message

Robbi

unread,
Jul 2, 2023, 5:52:27 PM7/2/23
to Chromium Extensions
I was having a couple of thoughts about the contextMenu API.
Probably someone has already done the same reflections, but I have not found anything similar in the group.
1) Why not expand the domain of the "contexts" field to a specific selection of nodes made through a CSS selector? (i.e "context":["table#foobar td > span"])
In the past I had to assign a wide context (["page")) and then, when the target of the menu was not among those enabled, I sent a message on the video.
It is not too beautiful; The user might ask: "Why did the developer have not previously disabled this menu on these elements?"

2) it would be useful to have within the object "info" of the onClicked callback the information of the genealogy of all ancestors.
The info could assume this form: grandfatherId~...~...~parentMenuitemId~menuitemId and could be called "pathMenuitemId" or "anchestorsMenuItemid".
It would be useful in my opinion to understand quickly if you clicked on any leaf of any branch without having to know how the entire tree is built.
Normally I create a static hierarchical structure (an object) and then, from it I create the various menus in a recursive way.
However, when the structure changes because items are removed or added then it could be useful.

3) connected to the previous point.
If you can't to add this kind info then perhaps you should add a "get" and\or "getAll" methods to obtain the same info by my own. ("pathMenuitemId").

Do you think my arguments are valid?

----------------------------------------------------

Off-topic question
Are someone rewriting Google Translate algorithms?
I have been getting paradoxical translations for a few days and therefore I had to dust off my (bad) school knowledge.

Max Nikulin

unread,
Jul 3, 2023, 6:13:00 AM7/3/23
to chromium-...@chromium.org
On 03/07/2023 04:52, Robbi wrote:
> *1)* Why not expand the domain of the "contexts" field to a specific
> selection of nodes made through a CSS selector? (i.e
> "context":["table#foobar td > span"])
> In the past I had to assign a wide context (["page")) and then, when the
> target of the menu was not among those enabled, I sent a message on the
> video.
> It is not too beautiful; The user might ask: "/Why did the developer
> have not previously disabled this menu on these elements?/"

Have you considered the onShown event and the refresh() method
implemented in Firefox?
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/menus/onShown

They should allow to inject a content script when the user opens a
context menu and to update menu accordingly to current
document.activeElement. At first glance it is an alternative to your
proposal.

From my point of view, a limitation of onShown current implementation
is that the event is fired only when the top level context menu is
shown. As a result content scripts are executed even when the user is
not going to select the submenu related to the extension. Event
listeners might be called when each level of submenu is displayed.

However cross-origin frames may be inaccessible for content scripts even
a menu is opened inside an <iframe>
https://crbug.com/523572
"Extend activeTab to frames for use in contextMenus"

Robbi

unread,
Jul 3, 2023, 8:08:04 AM7/3/23
to Chromium Extensions, Max Nikulin
The management of the contextual menu in Firefox is in many points different from that of Chrome; Maybe that's why they use two different namespaces.
The possibility of refreshing an item of the menu on the fly is a decidedly valid thing that I would like to see in Chrome in the future.
The page you reported also leads to a practical example  menu-labelled-open.
Example shows how to act in time on the menu.
The menu is shown solely when the link has a valid URL (extracted from "info) and in the opposite case it shows nothing.
If "info" also reported the information of the clicked node, (and if Chrome would allow you to update the menu tree on the fly) I could then have total control on the appearance of the menu.
Unfortunately it is not so :-(

In point 1  I wonder if it will ever be possible to restrict the appearance of the menu to a precise set of elements \ nodes decided in advance through a CSS selector.
For now, in Chrome it is possible to choose these values as Context: "All", "Page", "Frame", "Selection", "Link", "Editable", "Image", "Video", "Audio", "Launcher "," Action ".
So, either I take too much or take too little

Max Nikulin

unread,
Jul 4, 2023, 11:57:10 AM7/4/23
to chromium-...@chromium.org
On 03/07/2023 19:08, Robbi wrote:
>
> In point 1  I wonder if it will ever be possible to restrict the
> appearance of the menu to a precise set of elements \ nodes decided in
> advance through a CSS selector.

Perhaps you may make your proposal more convincing by providing several
examples of extensions that would benefit from the suggested addition.

My idea was to take the more general and already tested way. However I
have not checked whether some serious defects have been recognized in
the extra "menus" methods implemented by Mozilla.

Robbi

unread,
Jul 7, 2023, 5:58:19 AM7/7/23
to Chromium Extensions, Max Nikulin
I guess something like this could, somehow, limit the appearance of the context menu even if it's not the same thing I was talking about above

window.addEventListener('DOMContentLoaded', _ => {
document.getElementsByTagName("body")[0].addEventListener("contextmenu", e => {
var divElm = e.target.closest('DIV');   //I get the nearest ancestor node which should contain all nodes enabled for menù viewing
if (divElm?.id !== 'divCalendario')       //if that anchestor is outside\foreign to my scope I prevent the menù from being displayed
e.preventDefault()
})
})

Oliver Dunk

unread,
Jul 7, 2023, 6:04:16 AM7/7/23
to Robbi, Chromium Extensions, Max Nikulin
Definitely some interesting thoughts here.

Why not expand the domain of the "contexts" field to a specific selection of nodes made through a CSS selector?

I could see the utility for this.  The discussion between having predefined CSS selectors and a code block like in the last reply is interesting, I see the pros and cons of both.

it would be useful to have within the object "info" of the onClicked callback the information of the genealogy of all ancestors.

Do you have an example of a use case for this?

If you can't to add this kind info then perhaps you should add a "get" and\or "getAll" methods to obtain the same info by my own. ("pathMenuitemId").

Personally I've definitely felt like ways of seeing which context menu items exist is a big missing part of the API. Would love to fix that at some point.
Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB


--
You received this message because you are subscribed to the Google Groups "Chromium Extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-extensions/a5979f82-a0cc-426e-a15b-314e99cfeac3n%40chromium.org.

Max Nikulin

unread,
Jul 7, 2023, 8:43:36 AM7/7/23
to chromium-...@chromium.org
On 07/07/2023 16:58, Robbi wrote:
> window.addEventListener('DOMContentLoaded', _ => {
> document.getElementsByTagName("body")[0].addEventListener("contextmenu", e => {
> var divElm = e.target.closest('DIV'); //I get the nearest ancestor node which should contain all nodes enabled for menù viewing
> if (divElm?.id !== 'divCalendario') //if that anchestor is outside\foreign to my scope I prevent the menù from being displayed
> e.preventDefault()
> })
> })

I am curious what happens when chrome.contextMenus.update is called
while a context menu is open. I have in mind doing it from
chrome.runtime.onMessage and calling chrome.runtime.sendMessage from a
"contextmenu" event listener. (A hope that Mozilla's menus.refresh() is
not necessary for Chrome.)

Since you need context menu for pages from your extension and so you
have control on scripts loaded by such pages, have you considered using
Web API custom context menu without relying on extensions'
chrome.contextMenu? Such approach should allow to add a workaround for
opening context menu from keyboard when caret browsing (keyboard
navigation) is used.

A downside (if I understand it correctly) is that page JS can not just
add an entry to the default context menu. The only possibility is to
replace it completely. From this point of view e.preventDefault() may
break user expectation to get standard menu items (e.g. copy) or entries
added by other extensions.

Robbi

unread,
Jul 7, 2023, 8:48:10 AM7/7/23
to Chromium Extensions, Oliver Dunk, Chromium Extensions, Max Nikulin, Robbi
Hi @Oliver and thank you for your peply.

> Do you have an example of a use case for this? <

Sure, please conside that menù tree.

Root --> command --> Cancel -> Lastp op
--> Last 5 ops
--> All
--> Mark to be --> Deleted
--> Renamed
--> Copyied
--> Send
--> Other Stuff --> Navigate to --> Facebook page
--> Tweeter page
Style the page -->
Random body color
--> Zoom In
--> Zoom Out
--> Credits

Let's assume that the id of each menu item (parent and child) is composed of the description from which the spaces are removed and the initial letters are capitalised.

Each leaf of this tree would have the pathMenuitemId property set like this:

01 Command~Cancel~LastpOp
02 Command~Cancel~Lastp5Ops
03 Command~Cancel~All
04 Command~MarkToBe~Deleted
05 Command~MarkToBe~Renamed
06 Command~MarkToBe~Copied
07 Command~Send
08 OtherStuff~NavigateTo~FacebookPage
09 OtherStuff~NavigateTo~TweeterPage
10 OtherStuff~StyleThePage~RandomBodyColor
12 OtherStuff~StyleThePage~ZoomIn
13 OtherStuff~StyleThePage~ZoomOut
14 Credits

Let's say I wants to do something when the user clicks on one of the first 7 leaves.
The most efficient thing I can think of is to check if menuParentItemId is between "Cancel", "MarkToBe" and "Command" so the test can be written like this
["Cancel", "MarkToBe", "Command"].includes(info.parentMenuItemId)

...but I had a new pathMenuitemId property I could have written differentlylike:
pathMenuitemId.split("~").includes("Command")

If we consider that the tree can be destroyed, rebuilt and still change dynamically based on the user's choices\iterations (the developer may not have saved (or lost) the current tree structure)
it would be much easier then to check tree branches like: pathMenuitemId.split("~").length == 3
(that is: tree leaves that have a parent and also grandparents) )
How else could this last condition be written with only the "menuItem" and "menuParentItem" properties?

Oliver Dunk

unread,
Jul 7, 2023, 8:54:14 AM7/7/23
to Robbi, Chromium Extensions, Max Nikulin
So this makes sense, but I'm still not sure I see the actual use case (i.e when would you want to do this).

Presumably Command~Cancel~LastpOp and Command~Cancel~Lastp5Ops would need to call different functions or at least have different parameters. If you really want to group them together, you could just do ["lastpop", "lastp5ops"].includes(menuItemId) by having an array of all of the possible menu item IDs.
Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB

Robbi

unread,
Jul 7, 2023, 9:16:27 AM7/7/23
to Chromium Extensions, Oliver Dunk, Chromium Extensions, Max Nikulin, Robbi
@Oliver
you have right, normally any menu item call a different function,
but I could deactivate a whole submenù if any on "Command" sub-items is clicked.
How do i know how many children and grandchildren the "Command" branch has if this tree changes dynamically?
I could certainly know it in the initial conditions

As I said before, the developer don't always know the structure of the tree (unless he does keep track of it)
However I think less conditions would be written (and less code)


@Max
> have you considered using Web API custom context menu without relying on extensions' chrome.contextMenu? <
Sure, I normally use the contextMenu API for things strictly related to the extension and I try to avoid using it for other things.
This is also because I think it's not nice to see a menu appear with a series of items (I mean those of the OS) not relevant to the context in which that menu is used (in the specific case that I am experimenting with an html table)

Robbi

unread,
Jul 7, 2023, 9:32:22 AM7/7/23
to Chromium Extensions, Robbi, Oliver Dunk, Chromium Extensions, Max Nikulin
> I am curious what happens when chrome.contextMenus.update is called  while a context menu is open. <
Like Muzio Scevola did, I'm ready to put my hand in the fire and bet that the menù won't be resfreshed on the fly but only after its closure

Oliver Dunk

unread,
Jul 7, 2023, 10:41:59 AM7/7/23
to Robbi, Chromium Extensions, Max Nikulin
but I could deactivate a whole submenù if any on "Command" sub-items is clicked.

Hmm, pathMenuitemId wouldn't help here would it? You would only get the path for the one you clicked on, and you would still need some sort of get method in order to figure out the other children.
Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB

Robbi

unread,
Jul 7, 2023, 10:59:07 AM7/7/23
to Chromium Extensions, Oliver Dunk, Chromium Extensions, Max Nikulin, Robbi
I totally agree with you, we also need a get or getAll method.
These things should go hand in hand.

On the other hand, I realize that the vast majority of cases involve a static menu with a maximum of two levels and no more than 2-3 items.
I think it's definitely more important to fix the bugs already reported and put feature requests at the bottom of the "to-do" list.

Max Nikulin

unread,
Jul 13, 2023, 8:03:46 AM7/13/23
to chromium-...@chromium.org
On 07/07/2023 20:16, Robbi wrote:
> but I could deactivate a whole submenù if any on "Command" sub-items is
> clicked.
> How do i know how many children and grandchildren the "Command" branch
> has if this tree changes dynamically?

Frankly speaking, your use case is obscure for me.

Why to not do chrome.contextMenus.update(onClickData.parentMenuItemId, {
enabled: false }) to disable the whole group?

> I could certainly know it in the initial conditions
>
> As I said before, the developer don't always know the structure of the
> tree (unless he does keep track of it)
> However I think less conditions would be written (and less code)

At which moment do you build menu structure if you do not have enough
data in chrome.storage?

> 01Command~Cancel~LastpOp
> 02Command~Cancel~Lastp5Ops
...
> 06Command~MarkToBe~Copied
> 07Command~Send
...

> ...but I had a new *pathMenuitemId *property I could have
> written differentlylike:
> *pathMenuitemId.split("~").includes("Command")*

Sorry, I have not got if you use numerical menuItemId or strings? If
menuItemId is "Command~Cancel~Lastp5Ops" then you know all parent items:
"Command~Cancel" and "Command".

Max Nikulin

unread,
Jul 13, 2023, 8:14:41 AM7/13/23
to chromium-...@chromium.org
On 07/07/2023 17:03, 'Oliver Dunk' via Chromium Extensions wrote:
>
> If you can't to add this kind info then perhaps you should add a
> "get" and\or "getAll" methods to obtain the same info by my own.
> ("pathMenuitemId").
>
> Personally I've definitely felt like ways of seeing which context menu
> items exist is a big missing part of the API. Would love to fix that at
> some point.

Perhaps `get` for a checkbox item would allow simple extensions (that do
not need to sync settings across profiles) to avoid tracking its state
in chrome.storage.local through listening contextMenus.onClicked.
(On the other hand I have seen recommendation to call removeAll and to
recreate menu from scratch on update to ensure that all newly introduced
items are created.)

Another use case for `get` may be testing that menu has not been lost in
scenarios like update in disabled state or when incognito mode is
involved. For example, it should avoid using `update` to check existence
https://stackoverflow.com/questions/33834785/chrome-extension-context-menu-not-working-after-update

Robbi

unread,
Jul 13, 2023, 8:39:33 AM7/13/23
to Chromium Extensions, Max Nikulin
> Sorry, I have not got if you use numerical menuItemId or strings? If menuItemId is "Command~Cancel~Lastp5Ops" then you know all parent items: "Command~Cancel" and "Command". <

I wrote in my first post. (darkgreen background section)
Each menu item has an ID that does not report the information of its ancestors.

It could be a good idea to create the tree with ID that report the entire genealogy.
However, it would not solve all the problems since the tree can be dynamically created\modified and therefore with only the menuitemid and parentmenuid properties I will be able to get at least the grandfather info of any leaf (and no longer behind).

Let's say that with a two \ three level menu we can do everything without any effort.
My intent was to open the imagination to a tree with many branches and many levels.
That is, we can see the finger or the moon ...


Reply all
Reply to author
Forward
0 new messages