How can I make a userscript run inside an iframe?
In Greasemonkey (And Tampermonkey and most userscript engines) a script will fire on an iframe automatically if it meets the @include, @exclude, and/or @match directives.
And, a popular question is how to stop Greasemonkey from firing on iframes.
So, if your script had a match like:
@match https://fiddle.jshell.net/*
It would fire on jsFiddle "output" pages whether or not they appeared in an iframe.
Then you would check the window.self
property.
For example, suppose you had a target page like:
<body> <h1>I'm some webpage, either same-domain or not.</h1> <iframe src="//domain_B.com/somePath/somePage.htm"> ...
Then you could use a script like:
// ==UserScript== // @name _Fires specially on domain_B.com iframes // @match *://domain_B.com/somePath/* // ==/UserScript== if (window.top === window.self) { //--- Script is on domain_B.com when/if it is the MAIN PAGE. } else { //--- Script is on domain_B.com when/if it is IN AN IFRAME. // DO YOUR STUFF HERE. }
With the release of Greasemonkey 4, iframes handling is severely crippled (and many other things are broken, besides).
It still works properly with Tampermonkey, Violentmonkey and just about every other userscript engine.
It is strongly recommended (including by Greasemonkey itself) that you do not use Greasemonkey 4 or later.
This is a solution for cases where the iframe
has no location to trigger @include
or @match
.
This works with Greasemonkey 4.
We must wait for each frame to be loaded before we can operate on it. I do this by using waitForKeyElements.js
, which waits for elements matching a given CSS selector, just like looping through the matches in document.querySelectorAll("selector")
, and then applies a given function to the response:
// ==UserScript== // @include https://blah.example.com/* // @require https://git.io/waitForKeyElements.js // ==/UserScript== function main(where) { // do stuff here with where instead of document // e.g. use where.querySelector() in place of document.querySelector() // and add stylesheets with where.head.appendChild(stylesheet) } main(document); // run it on the top level document (as normal) waitForKeyElements("iframe, frame", function(elem) { elem.removeAttribute("wfke_found"); // cheat wfke's been_there, use our own for (let f=0; f < frames.length; f++) { if (!frames[f].document.body.getAttribute("been_there")) { main(frames[f].document); frames[f].document.body.setAttribute("been_there", 1); } } });
Note that the selected element is just a placeholder indicating that an iframe
has loaded. We remove the "been there" tracker from waitForKeyElements
because the frame may be loaded again later (we can't just use that iframe
because its contents are loaded elsewhere).
When we know a frame has loaded, we loop through each frame and look for our marker, an HTML attribute in the frame's body
called been_there
(like <body been_there="1">
). If it is missing, we can run our main()
function on the frame's document. When we're done, we add the been_there
attribute so we don't get triggered again.
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