I am writing a plug-in for Firefox and using greasemonkey script to do that (I compile the user script using this tool http://arantius.com/misc/greasemonkey/script-compiler).
The issue is that the script is run after the page is fully loaded. Meaning the user would see the viewed page in its original form and then the script will apply the changes that I made. My question is there a way to run the user script before the contents of the page is displayed to the user, so the user would only the final version of the website?
EDIT: This post was created prior to the implementation of the #run-at key in Greasemonkey - as noted by Blaise, from Greasemonkey 0.9.8 you may now have the script executed as soon as the page begins to load.
#run-at document-start is described in the wiki as follows:
Start is new as of version 0.9.8. The script will run before any
document begins loading, thus before any scripts run or images load.
Note that this means having the script run (potentially) prior to the creation of the DOM and may lead to some inconsistent/unusual behaviour. You will need (a little) more than just this one-line drop-in.
There are a few more details over at the Greasemonkey Wiki:
http://wiki.greasespot.net/Metadata_Block#.40run-at
Side-note: The information I have to hand is specifically related to Greasemonkey in the browser. I am unsure whether #run-at document-start works well with the script compiler - I suggest living dangerously.. Test it and find out! ;]
It is not currently possible to run a user script before the page loads.
To stop the flicker using current versions of Greasemonkey, you could try adding a user-style to your Firefox profile (which is then undone using the script) as described at the Greasemonkey wiki but this would also require each of your users to do the same to benefit from this.
It is something that has been desired for a long time and looking through issue #1103 on Greasemonkey's Github site, a working prototype appears to have been made (but there is no timescale for this to be added to a release version afaik).
In addition to the previous answers I've found a solution that works flawlessly, just like previous versions of Firefox & GreaseMonkey.
First off, run-at must be set to the earliest moment, so document-start:
// #run-at document-start
Because the DOM is probably not loaded yet, wait for the document to get a readyState of interactive:
document.onreadystatechange = function () {
if (document.readyState === "interactive") {
// Do something
}
}
While Greasemonkey implements more or less the same with document-end, I've noticed that the technique above works faster.
Using this has resolved all issues I had in Firefox with flashing / jumping screens on pages when the DOM changes kicked in and directly loads the page as intended with the userscript.
Using the #run-at document-start as suggested in the answer by #kwah my script executed before the content I wanted to manipulate was in the document body. As a work-around I set up an interval running my script 5 times/second until document.readyState == "complete" (or until 20 seconds have passed).
This worked well for my case:
// ==UserScript==
// ...
// #run-at document-start
// ==/UserScript==
var greasemonkeyInterval = setInterval(greasemonkey, 200);
var greasemonkeyStart = (new Date()).getTime();
function greasemonkey() {
// ...
// waiting for readyState (or timeout)
if (
(new Date()).getTime() - greasemonkeyStart > 20000
|| document.readyState == "complete"
) {
clearInterval(greasemonkeyInterval);
}
};
If you're more sure about that the content will be there at documentready I think something like this would be more preferable:
function greasemonkey() {
if (
document.readyState != "interactive"
&& document.readyState != "complete"
) {
return;
}
// ...
clearInterval(greasemonkeyInterval);
}
Related
I have a super simple script (running in a Userscript manager for Safari) that works on some pages but not all.
Here is the script:
// ==UserScript==
// #name Close tab on double click
// #include https://*
// ==/UserScript==
document.addEventListener("dblclick",function (event) {
window.close();
});
For some reason, it works on Stack Overflow, Reddit post pages, etc., but does NOT work on Reddit homepage, Google (homepage or search results), etc.
Why?
Thanks for any insight. I'm still a newbie about javascript.
Edit: Working now, using the GM.closeTab permission from my Userscript manager, as documented here: https://github.com/quoid/userscripts#api
Try using
// #grant window.close
in order to use window.close per the documentation.
In a chrome browser, when I add the JS function in the console and then double click on the page I get this notification (I tried the stack overflow site):
Console Image
My guess is your userscript manager may add the script you write differently depending on the website, and the websites that don't work are because of this warning. Try opening your console after you add the script and see if you get this warning when double clicking does not work.
I am trying to start an embedded videojs video using Greasemonkey. The video is running in a iframe and I managed to start the video in chrome with Tampermonkey but in Firefox the video starts loading and stops a sec later. I guess my following script starts too soon after reloading the page so I tried to delay the start with setTimeout but the code won't start. So my question is it possible to use setTimeout inside an iframe?
// ==UserScript==
// #name Autoplay
// #namespace openload
// #include https://openload.co/embed/*
// #version 1.0.0
// #run-at document-idle
// ==/UserScript==
window.setTimeout(play, 5000);
function play()
{
console.log("Start");
document.querySelector('#videooverlay').click();
videojs.getPlayers()['olvideo'].player_.play();
console.log("End");
}
I use #include https://openload.co/embed/* to run the script inside the iframe otherwise I can't use the command .play().
If I open the iframeurl manually and use the commands over the FF console it works perfectly.
Maybe try something like this
window.addEventListener ("load", playerstart, false);
function playerstart () {
}
I think you would want to add an "onload" event listener to the page loading in the iframe, and in the load function add the setTimeout.
I think the bigger issue to to figure out why it's not playing in Firefox. Is it an encoding issue? Do you have it in a source that FF can play? Miro Video Converter can help.
Do you tryed to start the script on the parent and inside the iframe? Then use setTimeout.
I've been doing some testing with http://www.webpagetest.org/ today to see which scripts are slowing down my page loads. Long story short, I've discovered that third-party scripts are causing a noticeable slowdown in loading. I'm loading them all at the bottom of the page, using async and defer ( see https://www.igvita.com/2014/05/20/script-injected-async-scripts-considered-harmful/ ).
I believe the main reason for the slowdown is not just in grabbing the files from the third-party, but in actually running the various scripts, especially side-by-side with mine.
I'd like to keep all the scripts, but I want them to be loaded behind the scenes, after all my scripts have loaded, and with no noticeable performance decrease in the browser. For example I don't want the browser to "stutter" or jump around if I start scrolling down while the third-party scripts are loading, or various other minor annoyances.
Has anyone tackled this before and come up with a good solution? So far I'm thinking the best option might be to load the third-party scripts using jQuery.getScript(), after all my scripts have finished (literally at the bottom of one of the .js includes). Still, that may load them all concurrently which could make the browser sluggish for a second or two.
Some more details on how I did the testing, for anyone interested:
grabbed the source code of a product page, threw it into a test PHP page so I could modify it at will
surrounded each script with an on/off flag such as
if ( isset( $_REQUEST["allowGoogleAnalytics"] ) ) {
ran a test with all scripts turned off
in new tabs, ran more tests, turning scripts on one at a time
by the time my own scripts were all turned on, the pages were taking about 1.9 seconds to load (first view) and less than a second on repeat view. This is fine with me.
after turning on the third-party scripts, the pages were taking at least 3.1 seconds to load (first load) sometimes as much as 3.9
The third party scripts in question are:
facebook "like" button
google +1 button
pinterest
google trusted stores
None of these are particularly bad on their own, but all at once they combine and take too long, and make the browser too sluggish.
You can queue scripts, if problem is in simultaneous load. Also this load should be started on document ready (i see you already using jQuery, so use it in example).
Example code (tested locally, works).
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
var scripts2load = [
"http://apis.google.com/js/plusone.js",
"http://connect.facebook.net/en_US/all.js#xfbml=1"
];
function loadNext() {
var url = scripts2load.pop();
if (url) {
$.ajax({
url: url,
cache: true,
crossDomain: true,
dataType: "script",
success: loadNext
});
}
}
$(loadNext)
</script>
In the past I have had some success waiting until the page was fully loaded (which happens after DOM Ready). Any scripts that you load before window.load causes the browser to do more work on top of the parsing/rendering/resource loading it's already doing. Traditionally, we do everything on DOM ready - which can quickly give the browser a lot to deal with. Instead, split off any of your non-crucial functionality and let the browser deal with them after all the crucial stuff has been dealt with.
Try taking your non-crucial scripts (eg. like buttons, anything not crucial to the page) and wait to load them until window.load. Then apply a fade-in effect or something else to ease-in the display. If window.load is too long to wait (ie. you have a bunch of images on your page), then you can do something like this:
$(function() {
var timer = setTimeout(loadThirdPartyScripts, 1200),
$window = $(window);
$window.on('load.third_party', loadThirdPartyScripts);
function loadThirdPartyScripts() {
clearTimeout(timer);
$window.off('load.third_party');
/* load your scripts here */
}
});
This will load all of your non-crucial scripts after the window has loaded or after 1.2 seconds - whichever comes first (adjust the timeout as needed). If you have a lot of images - I suggest lazy loading ones below the fold - the whole point being to get window.load to fire as soon as possible.
Disclaimer: if you wait until window.load to load a dozen or two resources, you are still going to experience the same stutters that you are now.
i have this code:
==UserScript==
// #name name
// #namespace url
// #description desc
// #include http://www.facebook.com/*
// #require http://code.jquery.com/jquery-1.5.2.min.js
// ==/UserScript==
$(document).ready(function() {
$("a").click(function(){
alert(1);
return false;
});
});
but when i install it, and click on some link i'm just taken to the adress, which means the script doesn't work.
can anyone tell me where's my mistake?
Your code looks fine and works for me on FF 4.0.1 with GM 0.9.2. You haven't specified the Firefox or GM version that you're working with - but I think I remember running into a problem where the external scripts would not get loaded. You might try copying and pasting the entire minified source of jQuery into your GM userscript, just after the header, before your code.
You might also want to make sure your code actually does get loaded by putting in some log/alert statements - I'd suggest $().jquery at least to ensure you have jQuery loaded and check it's version.
I have created a Greasemonkey script that runs fine in the firebug editor, with the Greasemonkey specifics removed, but not when I try to package it as a userscript. The Firefox error console is reporting that an iframe I am trying to use is undefined.
I've cut the userscript down to a minimum case where it should be printing the iframe html into the firebug console, and does when run in the firebug editor, but is not working as a userscript:
// ==UserScript==
// #name Movies
// #include http://*.princecharlescinema.com/*
// #include http://princecharlescinema.com/*
// ==/UserScript==
// stop script loading multiple times
if (top !=self) return;
var iframeHTML = window.frames['iframe2'].document.documentElement.innerHTML;
unsafeWindow.console.log(iframeHTML);
An example page the script is intended for
If it's of any use the gist of the full script is I collect all the td tags from this iframe, get some information from them, and then insert some new html into some of the same td tags.
Any help would be appreciated.
Perhaps you need to wait for DOMFrameContentLoaded