New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Execute in frames #2574
Comments
Potential solution for greasemonkey#2574
webNavigation.onCommitted doesn't 'see' initial frame creation / page rendering, though if the frame navigations someplace other than its initial page then the listener will catch it. If options were to include the key The easiest solution I could think of would be to replace webNavigation.onCommitted with webRequest.onResponseStarted with a filter of I did some limited testing and no further changes were needed. I was able to execute a script within a frame and a frame created using Javascript. |
Potential solution for greasemonkey#2574
Missed this, will look into it soon. |
Potential solution for greasemonkey#2574
Just an observation during my testing of old scripts, don't know, if it helps... Given a script, that is supposed to work on an iframe, I can only see the flickering when I refresh the page very fast. |
Is this with my patch or with the released version? |
Ugh, I think it was 4.0 release... |
Same here with iframes like Eselce describes. In some way it is executed, but then stopped after the iframe or page is loaded. If I inject this script, I only get 1 and "self !== top": console.log('1');
if (self !== top) {
console.log('self !== top');
setTimeout(function() {
console.log('Timeout');
}, 2000);
} else {
console.log('self === top');
} "Timeout" is not shown in the log, neither all functions and binds are. I use 4.1b3. |
I have the same issue running GM 4.0 on Quantum. I wrote a very simple dummy example with two pages: Most of the time, I only get notifications about Is there any hack to reliably force GM 4.0 to execute inside iframes until a patch is out? |
I just found out that userscripts are reliably executed in |
Potential solution for greasemonkey#2574
Some more details: In some cases, my scripts are completely executed in the frame (but the view is overwritten later by page scripts and so). |
Has anyone more infos on this? Just a short summary of this thread (issue):
I'm not so much into these internals, but probably someone is... |
As a temporary fix, I've been swapping out iframes for embeds (example script), which does work to get a script corresponding to the frame to trigger (credit to @cvzi for figuring out that |
It might be worth noting that Violentmonkey and Tampermonkey work just fine inside embedded frames. Since VM is open source, maybe see how they did it? |
@RyanHanekamp Thanks for the tip! Perhaps I will use Violentmonkey for some scripts, then. Does Violent also have something like synchronous GM_getValue? That's another problematic issue that breaks a ton of scripts in the new Greasemonkey. I still trust Greasemonkey the most, though, for various reasons, so I won't leave it. As to iframes, I've been trying to replace them with object tags, which one can apparently access directly using Javascript, like so:
Then, once the object is loaded: |
I'm not a VM expert, but I believe it does implement at least most of the original GM_* API. I would think it's better to adapt your scripts to asynchronous than to backtrack to a synchronous platform in the long run, though. Per my understanding, Greasemonkey did this as a performance boost within the new Quantum framework, which doesn't allow synchronous calls between background and content scripts. As for the object solution, it won't solve my particular problem, but I'm glad others have found it useful. Aside from marshaling CSS / properties / etc and getting it to work with frames as well as iframes, I have to filter out objects in a capture process as potentially unsafe. There are ways around all of these problems, but VM was the easier interim until GM finally does what it says on the tin. Also, if you have a same-origin frame/iframe, you can access the content ofthose directly as well. The harder part is cross-origin, which is why I need userscripts inside the frame. It sets up a window.postMessage() channel to talk back to the parent window. |
@RyanHanekamp Good to know that Violent Monkey still has the old, simple GM_*. I really wish Greasemonkey had kept the old, synchronous GM_getValue for backward compatibility, in addition to the new version. I might try to implement the new asynchronous function in a new script, but I'm not a programmer and I'm not sure whether I could make it work. And I am certainly unable to refactor the use of old GM_getValue in an ancient script of 2000 lines that I found online...so many scripts are broken now. I understand why Violent was the better option for you. Let's hope Anthony or Sxderp or someone else finds out how to do implement this eventually. I really wish I could contribute, but I'm a total layman. Oh, you can directly access the content of a same-origin iframe (without postMessage etc.)? I remember spending a lot of time trying to find a way, but it didn't seem possible. That's why I switched to postMessage as well. |
Frames and iframes have a contentWindow property that's equivalent to the window property. Both have a document property to access the DOM. The hardest part of working with iframes (on the same origin) is detecting when its content is loaded, because you can't do squat until that happens. onload doesn't work how it looks. Firefox provides a DOMFrameContentLoaded event that fires for EVERY frame loaded, including grandchild / great-grandchild etc frames, which you can match to the original frame / iframe element with the event.target property. If you control the content of the frame/iframe, you can also have it talk back to the parent with either postMessage or calling a global method on the window.parent object. Speaking of which... that's a potential workaround for this issue. If there is or could be a way to code a GM script to manually inject a userscript into a cross-domain window reference, it would take a lot more coding for the userscript creator, but it could get the job done. The pattern would be listen to DOMFrameContentLoaded, check if the event.target is first-generation, and manually inject the script if so. (Presuming that the first-generation frame's script can listen to DOMContentLoaded for second generation frames, and thus get a complete chain.) There would be no way to get @run-at dom-start behavior, and there might also be timing issues, but we could probably work around those for most use-cases. |
I've personally given up on this issue ever being resolved, and have instead moved on to directly coding an extension. Which works fine in all frames! The difference between Greasemonkey and Violentmonkey on this point seems to be that Violentmonkey is being triggered from content scripts with all_frames set to true, while Greasemonkey has no install-time content scripts and relies entirely on the dubious ability of the background script to sniff when a tab's frame has navigated. (And Violentmonkey fails on CSP pages because it temporarily injects a SCRIPT tag instead of using the far safer tabs.executeScript().) Put in a static content script with all_frames, run_at start, matches everything to notify the background process for start / document.DOMContentLoaded / document.Idle to trigger userscripts for each run_at, and you're good to go. A non-trivial but manageable amount of work to make this problem go away. I'd fix it myself, but I have no interest in plodding through your dev dependencies and could only produce the output code. |
Would you be willing to share that extension code of yours? |
My extension isn't general purpose. The point is that using a static content_script in the manifest with all_urls, all_frames will run the script whenever any frame is loaded or navigated, and can even eval / Function constructor code just fine regardless of the page's Content-Security-Policy. I have not tested with programmatically constructed frames / windows, but I would imagine they would run at initial creation regardless of the run_at setting, because such frames are initially created blank and then populated -- the engine would probably only see the initial creation. I also didn't test data: urls, which might require explicit matching -- I'm not sure if all_urls covers them, or just http/https. It might not have to be a static content_script reference, either, but it appears uncertain from the documentation if dynamically-invoked content scripts load automatically when the page is navigated. My impression is that they're only injected into currently matching tabs / frames per the supplied match pattern, and navigation doesn't trigger a re-injection. But I see no downside to using a static content_script for this purpose. Greasemonkey obviously can't include userscripts as static resources in the manifest, and content scripts don't appear to have direct access to tabs.executeScript (though I'm hardly an expert on this as I'm only a few days in), but what a static content script CAN do is message the background process to let it know that the frameId has been navigated, and to what URL. This would be more reliable than how I perceive the attempts mentioned on this thread to hook the right event in webRequest or webNavigation. The signal from the static content_script becomes the event we're looking for to trigger Greasemonkey's userscript loader / injector. There would possibly be a delay for userscripts that strictly MUST run_at document_start. The call to the background script is asynchronous, and the document will have progressed by the time the userscript is invoked. This is quite possibly why Violentmonkey uses a temporary script tag instead of tabs.executeScript, as the script tag injection can be done directly from the content_script, synchronously. I would find being forced to work around uncertainty of the document's state for run_at document_start to be troublesome, but preferable to the script not running at all. |
This is what we used to do for detecting But it turns out even extension content scripts can be broken by CSP (#2631 and http://bugzil.la/1267027 and http://bugzil.la/1411641). |
I can execute my own plugin, including a Function() constructor from directly within the content_script, on Firefox 60.0.1 and 52.8.1ESR with the following CSP set: frame-src data:; object-src 'none'; script-src 'none'; style-src 'unsafe-inline' data:; connect-src 'none'; media-src 'none'; #2631 has been closed, apparently because Firefox fixed its underlying bug. The first bugzilla is in reference to injecting script tags (the Violentmonkey method), not the content_script itself. The second is in reference to the sandbox attribute for CSP, not surprising because it forces the domain to never successfully complete a domain match even to itself. Kinda like NaN!==NaN. |
When this was first filed several months ago we did things differently. Today we use webNavigation.onCommitted to detect navigation, and in the test I'm running right now, for some reason I'm not seeing it trigger on a(n i)frame). |
Hello, is this solved now? I couldn't get a script I created for Tampermonkey to be launched on an iframe with Greasemonkey. |
The code for execution hasn't been changed on our side. So unless Mozilla has changed something on their end this is still broke. However #2663 should resolve it. |
Tampermonkey has problems with iframes in Chrome, at least for me. |
But it works for me in Firefox Violentmonkey. So I wonder how it can work there? I've just noticed that a script using the old sync GM_GetValue still works fine in Violentmonkey as well. How is that possible? I thought Firefox had forced async GM.GetValue? I'm so confused now: presumably Violentmonkey had to sacrifice something else in order to still support sync and the other stuff? |
@Cerberus-tm The change in Firefox meant that data can only be requested from extension storage or the background context asynchronously (the userscripts themselves are sent to the content script asynchronously). However, data could be provided to userscripts synchronously, if each GM4 content script prefetched and cached in the content script the data that's stored for each userscript being loaded in that page. Such a cache would allow the content script to respond synchronously to the userscript's requests for data. Implementing a cache runs into issues with maintaining consistency across the various content scripts, but that's resolvable by having the content scripts listen for all changes to GM4's extension storage. In addition, if a userscript is storing a large amount of data, then caching it in every content script where the userscript is run also significantly increases the memory required for each content script. TM and VM chose to do something similar to the above in order to not break compatibility with the original Greasemonkey APIs when those userscript managers were implemented for Chrome, which has the same restrictions wrt. asynchronous communication with extension storage, etc. Given that they are already doing it for Chrome, there was no reason for them to change when implemented for Firefox. So, the FF57 cut-over to WebExtensions did force a rewrite of GM, but it did not force the adoption of the asynchronous APIs for Personally, I feel that the choice, and other choices to break compatibility, were/are unfortunate. The lack of backwards compatibility with scripts which ran fine in GM3 and/or compatibility with TM result in many people choosing not to use GM4. My experience is that well more than 30 of the userscripts I use, all of which worked fine in GM3, don't work with GM4 (or at least didn't work prior to being rewritten to be compatible with GM4). There are still 28 userscripts I use daily which ran fine under GM3 which don't work with GM4. |
I posted a workaround to this issue on Stack Overflow as an answer to how to Apply a Greasemonkey/Tampermonkey/userscript to an iframe. Basically, I'm waiting for the frame to load, adding a listener to key on each load (including that first one) to run a function on the frame's contentDocument. Perhaps Greasemonkey could implement a solution in a similar manner? It'd be awesome if we also had a |
as fare as i can tell this does not work any longer to access the inside... |
@s-light: It still works for me on FF 106. You're doing something like this? waitForKeyElements("iframe, frame", function(frame) {
frame.addEventListener('load', function(e) {
let body = e.target.contentDocument.body;
// ... use `body` in place of `document.body`
}
} (I haven't tried using |
@s-light I had a similar cross-origin error because my script was not correct, you can see my answer explaining how I made it work: https://stackoverflow.com/questions/37616818/apply-a-greasemonkey-tampermonkey-userscript-to-an-iframe/75268492#75268492 |
…Cadres() + attendreEtRetaper(): fonction pour patienter le temps qu'un document ait tout le nécessaire pour qu'on le charcute (pour éviter d'appliquer nos modifs alors que la page est vide, puis ne pas le faire une fois qu'elle est pleine). + attendreEtRetaperDocEtCadres(): aussi pour les iframe (sous GreaseMonkey 4 un peu léger sur l'affaire, cf. greasemonkey/greasemonkey#2574). darcs-hash:a6ca49f435b1e3ff5d336500974bd245a5a68a7d
Greasemonkey 4 as of today only detects navigation events at the top level, so it effectively applies
@noframes
to every script.The text was updated successfully, but these errors were encountered: