Tampermonkey / tampermonkey

Tampermonkey is the most popular userscript manager, with over 10 million users. It's available for Chrome, Microsoft Edge, Safari, Opera Next, and Firefox.
GNU General Public License v3.0
4.29k stars 424 forks source link

[Feature] Message passing #874

Open qsniyg opened 4 years ago

qsniyg commented 4 years ago

I understand that feature requests aren't generally accepted, so I don't necessarily expect this to be implemented, but I'll explain why I believe a feature like this would be useful.

In my userscript, I use message passing in the extension version to transmit information between frames (e.g. mouse position, keyboard events), to allow the image popup to appear in the top frame, for an image inside a frame (well as a few other things).

While this is possible when using window.postMessage, it only works for frames that allow the host document to access the contentWindow, and causes a very significant privacy risk (especially when transmitting keyboard events).

A better solution would be to have an arbitrary message passing function, in a similar vein to GM_addValueChangeListener. While I understand that GM_addValueChangeListener can be used as a hacky way to do message passing, it would cause problems when the userscript is used in more than just one tab (save for rather ugly heuristics), let alone the possible performance problems when setting values 30-60 times per second (as the mouse moves).

Here is how I would imagine such an API could work:

GM_sendMessage({
  // Which instance to send the message to. Can be one of:
  //   - userscript instance ID (found through the sender property in GM_addMessageListener)
  //   - undefined|null for all instances of this userscript
  //   - "sameTab" for instances within the same tab (e.g. to subframes or the top frame), or alternatively, something like: {tabId: number}
  receiver: any,

  // A JSON-serializable object to send
  message: object
});

// sender: {
//   instanceId: number, // unique userscript instance ID, to be used with GM_sendMessage
//   tabId: number // to know whether it's from this tab or not
// }
// message is self-explanatory
GM_addMessageListener(function(sender, message) {});

// GM_info would contain `tabId` and `instanceId` to identify the current userscript

If you do want to implement this feature, I'm guessing you probably won't want to implement this API as I described. I added it only as a way to clarify the feature request :)

anonghuser commented 1 year ago

If you implement this, please consider the option to allow other user scripts to receive the message too. Currently there is no secure way for separate user scripts to communicate with each other. When it is needed, i.e. one script implementing some API to be used by others, currently we have to also expose the API to the web pages themselves, which may be undesireable. A messaging system internal to user scripts, not exposed to the websites' content windows, would be really appreciated, and can cover different use-cases with different combinations of "target" filtering options:

Additional useful target filters may be: all instances of a specific script by name or some global key, all instances of a specific script by local id (acquired from listener argument), only top frames, only the currently visible tabs in all windows or in the current or last focused window, etc. These are implementable in custom code if the basic ones above are provided, but it may be worth considering them in the core API too to reduce custom code.

On another note, is there a better place for posting or discussing new userscript feature ideas? It used to be the case that TM and others were just following GM so GM was the "leader" for user script feature decisions, but I think now TM is the leader, at least in user adoption.