Why does jQuery load twice in my GreaseMonkey Script - javascript

for some reason my Firefox4+GreaseMonkey Script loads jQuery twice. I copy'n'pasted the following snippet, the "test" alert shows twice.
Regards
var $;
// Add jQuery
(function(){
if (typeof unsafeWindow.jQuery == 'undefined') {
var GM_Head = document.getElementsByTagName('head')[0] || document.documentElement,
GM_JQ = document.createElement('script');
GM_JQ.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
GM_JQ.type = 'text/javascript';
GM_JQ.async = true;
GM_Head.insertBefore(GM_JQ, GM_Head.firstChild);
}
GM_wait();
})();
// Check if jQuery's loaded
function GM_wait() {
if (typeof unsafeWindow.jQuery == 'undefined') {
window.setTimeout(GM_wait, 100);
} else {
$ = unsafeWindow.jQuery.noConflict(true);
letsJQuery();
}
}
// All your GM code must be inside this function
function letsJQuery() {
alert("test");
}

This is probably because the target page is loading frames or iframes.
Add these lines to the top of the code-portion of your script:
if (window.top != window.self) //-- Don't run on frames or iframes
return;
Also, if you are just using FF + GM, don't bother with all that rigamarole to load jQuery. GM now works with the later jQuery versions.
Just add a line like:
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js
into your script's metadata block. jQuery will be copied once onto your local machine and run from there -- eliminating what can sometimes be a few seconds delay in your script's runtime.
And such scripts can run in Chrome, if you use one of the GM-emulating extensions like TamperMonkey.

Related

Error:Bootstrap's JavaScript requires jQuery

So i am working on a simple javascript widget and i started up by followinf this tutorial. I am loading jquery dynamically like below:
if (window.jQuery === undefined || window.jQuery.fn.jquery !== '2.1.4') {
UPDATE, Here is how i'm loading jQuery
var script_tag = document.createElement('script');
script_tag.setAttribute("type", "text/javascript");
script_tag.setAttribute("src",
"https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js");
document.documentElement).appendChild(script_tag);
//Once loaded load other javascripts
if (this.readyState == 'complete' || this.readyState == 'loaded') {
scriptLoadHandler();
}
}
Following is my scriptLoadHandler function:
function scriptLoadHandler() {
// Restore $ and window.jQuery to their previous values and store the
// new jQuery in our local jQuery variable
jQuery = window.jQuery.noConflict(true);
// Call our main function
main();
}
Now, in the main method i'm trying to load Bootstrap js like this:
function main() {
console.log("undefined" == typeof jQuery);
var head = document.getElementsByTagName("head")[0];
var js = document.createElement("script");
js.type = "text/javascript";
js.src = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js";
head.appendChild(js);
}
But it's still giving me above error even though the order in which they load is correct and when i check console log it gives me false which means jQuery is defined.
Check if JQuery is loaded before of bootstrap loading request. If JQuery is not already loaded bootstrap can not be loaded
//Load jquery here
You're not loading jQuery there.
You should either create a SCRIPT element in the DOM before this script with src your jQuery lib location, or load it dynamically after the line I've quoted (i.e. create the script tag, set the src to your jquery lib relative or absolute URL/URI, add the onloaded event handler to execute scriptLoadHandler and eventually append the new script to the DOM)
Easiest way is to load the script via a script TAG BEFORE the script you're using.
EDIT: after more information by OP, here is the solution:
check for the version of jQuery: if it's not the one you want, load it.
After you've loaded the jQuery version you need (or if it's already loaded), load Bootstrap.
JSFiddle: http://jsfiddle.net/1h6emjwu/2/
function loadScript(src, callback) {
var js = document.createElement('script');
js.src = src;
js.type = 'text/javascript';
if (typeof callback === 'function') {
js.addEventListener('load', callback);
}
document.body.appendChild(js);
}
var myScript = function () {
//alert(window.jQuery.fn.jquery);
alert($.fn.modal ? 'Bootstrap loaded' : 'Bootstrap not loaded');
}
if (window.jQuery === undefined || window.jQuery.fn.jquery !== '2.1.4') {
window.oldJQuery = window.jQuery; // so that you can return back whenever you want
loadScript('https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js', function () {
loadScript('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js', myScript);
});
} else {
loadScript('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js', myScript);
}

Load jquery dynamically before using jquery

My script will be using as widget in third-party website so i don't aware about jquery loaded and which version of jquery loaded or not at third-party end.
So Before loading below script i want to check is there already latest jquery 1.11.1 loaded after dom ready if not then i want to load the jquery latest and run below script.
script.js
var $ = jQuery.noConflict( true );
(function( $ ) {
$(document).ready(function() {
alert("Document Ready ");
});
})($jy);
EDIT 1
var addNewJQuery = function() {
(function( $ ) {
$jy = $;
var invokeOriginalScript;
$(document).ready(function() {
......my code here.....
}):
})(jQuery);
}
Not sure if this is working for you, but it looks like it is working.
Maybe you need to remove the other script from your header after you loaded the second jQuery file. But it seems to work with both scripts loaded.
I've also added a check if jQuery is loaded at all, if not it will load jQuery.
You can also find the same code in this fiddle.
var addNewJQuery = function() {
//var jQ = jQuery.noConflict(true);
(function ($) {
$(document).ready(function () {
alert("You are now running jQuery version: " + $.fn.jquery);
});
})(jQuery);
};
if ( typeof jQuery === 'undefined' ) {
alert('no jQuery loaded');
//throw new Error("Something went badly wrong!"); // now you could load jQuery
loadScript('https://code.jquery.com/jquery-1.11.2.js', addNewJQuery);
}
if ($.fn.jquery !== '1.11.2') {
console.log('detected other jQuery version: ', $.fn.jquery);
loadScript('https://code.jquery.com/jquery-1.11.2.js', addNewJQuery);
}
function loadScript(url, callback)
{
// Adding the script tag to the head as suggested before
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
// Then bind the event to the callback function.
// There are several events for cross browser compatibility.
script.onreadystatechange = callback;
script.onload = callback;
// Fire the loading
head.appendChild(script);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

Can't get jQuery to load in IE8 or IE9

I have a header that runs off a js file which can be included on other people's sites, however in IE8 and IE9, I get:
'$' is undefined
in the console.
My code only utilizes jQuery if it is IE8 or IE9 because of cross domain issues which are taken care of with the built in functions in the jQuery library. When browsing on WordPress sites the included script works fine, but on another site without jQuery loaded beforehand, it does not work, and the code I use to include jQuery in the header before loading the jQuery code also does not work.
var isIE = getInternetExplorerVersion();
if (isIE == 8 || isIE == 9) {
// Insert jQuery <script> to <head>.
var head = document.getElementsByTagName( 'head' )[0], script;
script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js';
head.insertBefore( script, head.lastChild );
// Run jQuery test
$('html').click(function(){
// Runs without issue on sites that ALREADY have jQuery loaded when IN IE.
alert('Clicked while in IE');
});
} else {
// Runs without issue when not on IE.
alert('Not in IE');
}
For those wondering, this is the function for figuring out the IE version (irrelevant in this case as it works):
function getInternetExplorerVersion() {
var rv = -1; // Return value assumes failure.
if (navigator.appName == 'Microsoft Internet Explorer');
{
var ua = navigator.userAgent;
var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
if (re.exec(ua) != null) rv = parseFloat( RegExp.$1 );
}
return rv;
}
You don't need to write custom code to check for the IE version. IE ships this "feature"(;
This is the solution from when jQuery 2.0 was released
<!--[if lt IE 9]>
<script src="jquery-1.9.0.js"></script>
<![endif]-->
<!--[if gte IE 9]><!-->
<script src="jquery-2.0.0.js"></script>
<!--<![endif]-->
More on conditional comments for Internet explorer here.
First of all, to solve your problem directly, you are loading the script asynchronously (read: out of order). Therefore, the code after you try loading jQuery doesn't necessarily mean jQuery is loaded at that point. Since you created a script element, you could attach an onload to it
script.onload = function(){
// This will execute when the script you loaded is loaded
}
To answer the other problem, as to why you're loading jQuery based on a browser version, I suggest you use the latest 1.x.x versions of jQuery. They are compatible with IE6+ as well as newer browsers. No need to check for versions.
Your script could have been condensed to:
;(function(ready){
if(jQuery) return ready();
var script = document.createElement('script');
document.head.appendChild(script);
script.onload = ready;
script.src = "path/to/jquery.1.x.x.js";
}(function(){
// Code here runs when ready
}));
First, thank you for all of your answers.
While they were helpfull they could not solve the issue since jQuery must exist on the page before this page is loaded, and injecting it into the head even after this js file is loaded will not work.
To solve the issue I've created another js file to come before this one. In that file it checks whether jQuery is on the page and the browser is one that is incompatible with our xdomain script and if it is, then we add the jquery file via script, and add the js file with all of our functionality afterwards.
File 1:
(function(ready) {
'use strict';
var isIE = getInternetExplorerVersion();
if ((isIE == 8 || isIE == 9) && window.jQuery) {
// On IE and jQuery exists
return ready;
} else if (isIE == 8 || isIE == 9) {
// On IE and jQuery doesn't exit
var head = document.getElementsByTagName( 'head' )[0];
var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js';
script.onload = ready;
document.head.appendChild(script);
return ready;
} else {
// Not on IE
return ready;
}
script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = 'http://www.test.com/path/to/other/js_file.js';
script.async = true;
head.insertBefore( script, head.lastChild );
})();
function getInternetExplorerVersion() {
var rv = -1; // Return value assumes failure.
if (navigator.appName == 'Microsoft Internet Explorer') {
var ua = navigator.userAgent;
var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
if (re.exec(ua) != null) rv = parseFloat( RegExp.$1 );
}
return rv;
}
File 2 (js_file.js from above):
(function(ready) {
var isIE = getInternetExplorerVersion();
if (isIE == 8 || isIE == 9) {
// Run jQuery test
$('html').click(function(){
// Runs without issue on sites that ALREADY have jQuery loaded when IN IE.
alert('Clicked while in IE');
});
} else {
// Runs without issue when not on IE.
alert('Not in IE');
}
})();

Adding jQuery by demand and use $?

I have a TextBox and a Button:
If the value inside the Textbox is 1 (just emulating a condition)) I need to load jQuery on the fly and use a document Ready function :
I tried this :
function work() //when button click
{
if (document.getElementById('tb').value == '1')
{
if (typeof jQuery == 'undefined')
{
var script = document.createElement('script');
script.src = "http://code.jquery.com/jquery-git2.js";
document.getElementsByTagName('head')[0].appendChild(script);
$(document).ready(function ()
{
alert('');
});
}
}
}
But it says :
Uncaught ReferenceError: $ is not defined
I assume it's because the line : $(document).ready(function ()....
But I don't understand why there is a problem , since i'm, loading jQuery BEFORE I use $...
Question :
How can I fix my code to work as desired ?
JSBIN
You are missing the script onload handler:
var script = document.createElement('script');
// do something with script
// onload handler
script.onload = function () {
// script was loaded, you can use it!
};
Your function becomes:
function work() {
if (document.getElementById('tb').value != '1') { return; }
if (typeof jQuery != 'undefined') { return; }
// jQuery is undefined, we will load it
var script = document.createElement('script');
script.src = "http://code.jquery.com/jquery-git2.js";
document.getElementsByTagName('head')[0].appendChild(script);
// load handler
script.onload = function () {
// jQuery was just loaded!
$(document).ready(function () {
alert('');
});
};
}
Also, do not forget script.onreadystatechange for IE compatibility.
script.onreadystatechange = function () {
if (script.readyState === 'loaded' || script.readyState === 'complete') {
// script was loaded
}
}
Also seems that YepNope would be a good option, too.
JSBIN DEMO
Using YepNope would probably a good option in this case.
yepnope([
{
test: window.jQuery,
nope: 'path/url-to-jquery.js',
complete: function() {
$(document).ready(function() {
//whatever you need jquery for
});
}
}
]);
You can just put that in the head of your document, and it will only load jquery if window.jQuery isn't defined. It's much more reliable (and simpler) than script.onload or script.onreadystatechange. the callback complete will only be called once jquery is loaded, so you can be sure that $ will be defined at that point.
Note: if you're using Modernizr.js on your site, there's a good chance yepnope is already bundled into that script.

Verify External Script Is Loaded

I'm creating a jquery plugin and I want to verify an external script is loaded. This is for an internal web app and I can keep the script name/location consistent(mysscript.js). This is also an ajaxy plugin that can be called on many times on the page.
If I can verify the script is not loaded I'll load it using:
jQuery.getScript()
How can I verify the script is loaded because I don't want the same script loaded on the page more than once? Is this something that I shouldn't need to worry about due to caching of the script?
Update:
I may not have control over who uses this plugin in our organization and may not be able to enforce that the script is not already on the page with or without a specific ID, but the script name will always be in the same place with the same name. I'm hoping I can use the name of the script to verify it's actually loaded.
If the script creates any variables or functions in the global space you can check for their existance:
External JS (in global scope) --
var myCustomFlag = true;
And to check if this has run:
if (typeof window.myCustomFlag == 'undefined') {
//the flag was not found, so the code has not run
$.getScript('<external JS>');
}
Update
You can check for the existence of the <script> tag in question by selecting all of the <script> elements and checking their src attributes:
//get the number of `<script>` elements that have the correct `src` attribute
var len = $('script').filter(function () {
return ($(this).attr('src') == '<external JS>');
}).length;
//if there are no scripts that match, the load it
if (len === 0) {
$.getScript('<external JS>');
}
Or you can just bake this .filter() functionality right into the selector:
var len = $('script[src="<external JS>"]').length;
Few too many answers on this one, but I feel it's worth adding this solution. It combines a few different answers.
Key points for me were
add an #id tag, so it's easy to find, and not duplicate
Use .onload() to wait until the script has finished loading before using it
mounted() {
// First check if the script already exists on the dom
// by searching for an id
let id = 'googleMaps'
if(document.getElementById(id) === null) {
let script = document.createElement('script')
script.setAttribute('src', 'https://maps.googleapis.com/maps/api/js?key=' + apiKey)
script.setAttribute('id', id)
document.body.appendChild(script)
// now wait for it to load...
script.onload = () => {
// script has loaded, you can now use it safely
alert('thank me later')
// ... do something with the newly loaded script
}
}
}
#jasper's answer is totally correct but with modern browsers, a standard Javascript solution could be:
function isScriptLoaded(src)
{
return Boolean(document.querySelector('script[src="' + src + '"]'));
}
UPDATE July 2021:
The accepted solutions above have changed & improved much over time. The scope of my previous answer above was only to detect if the script was inserted in the document to load (and not whether the script has actually finished loading).
To detect if the script has already loaded, I use the following method (in general):
Create a common library function to dynamically load all scripts.
Before loading, it uses the isScriptLoaded(src) function above to check whether the script has already been added (say, by another module).
I use something like the following loadScript() function to load the script that uses callback functions to inform the calling modules if the script finished loading successfully.
I also use additional logic to retry when script loading fails (in case of temporary network issues).
Retry is done by removing the <script> tag from the body and adding it again.
If it still fails to load after configured number of retries, the <script> tag is removed from the body.
I have removed that logic from the following code for simplicity. It should be easy to add.
/**
* Mark/store the script as fully loaded in a global variable.
* #param src URL of the script
*/
function markScriptFullyLoaded(src) {
window.scriptLoadMap[src] = true;
}
/**
* Returns true if the script has been added to the page
* #param src URL of the script
*/
function isScriptAdded(src) {
return Boolean(document.querySelector('script[src="' + src + '"]'));
}
/**
* Returns true if the script has been fully loaded
* #param src URL of the script
*/
function isScriptFullyLoaded(src) {
return src in window.scriptLoadMap && window.scriptLoadMap[src];
}
/**
* Load a script.
* #param src URL of the script
* #param onLoadCallback Callback function when the script is fully loaded
* #param onLoadErrorCallback Callback function when the script fails to load
* #param retryCount How many times retry laoding the script? (Not implimented here. Logic goes into js.onerror function)
*/
function loadScript(src, onLoadCallback, onLoadErrorCallback, retryCount) {
if (!src) return;
// Check if the script is already loaded
if ( isScriptAdded(src) )
{
// If script already loaded successfully, trigger the callback function
if (isScriptFullyLoaded(src)) onLoadCallback();
console.warn("Script already loaded. Skipping: ", src);
return;
}
// Loading the script...
const js = document.createElement('script');
js.setAttribute("async", "");
js.src = src;
js.onload = () => {
markScriptFullyLoaded(src)
// Optional callback on script load
if (onLoadCallback) onLoadCallback();
};
js.onerror = () => {
// Remove the script node (to be able to try again later)
const js2 = document.querySelector('script[src="' + src +'"]');
js2.parentNode.removeChild(js2);
// Optional callback on script load failure
if (onLoadErrorCallback) onLoadErrorCallback();
};
document.head.appendChild(js);
}
This was very simple now that I realize how to do it, thanks to all the answers for leading me to the solution. I had to abandon $.getScript() in order to specify the source of the script...sometimes doing things manually is best.
Solution
//great suggestion #Jasper
var len = $('script[src*="Javascript/MyScript.js"]').length;
if (len === 0) {
alert('script not loaded');
loadScript('Javascript/MyScript.js');
if ($('script[src*="Javascript/MyScript.js"]').length === 0) {
alert('still not loaded');
}
else {
alert('loaded now');
}
}
else {
alert('script loaded');
}
function loadScript(scriptLocationAndName) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = scriptLocationAndName;
head.appendChild(script);
}
Create the script tag with a specific ID and then check if that ID exists?
Alternatively, loop through script tags checking for the script 'src' and make sure those are not already loaded with the same value as the one you want to avoid ?
Edit: following feedback that a code example would be useful:
(function(){
var desiredSource = 'https://sitename.com/js/script.js';
var scripts = document.getElementsByTagName('script');
var alreadyLoaded = false;
if(scripts.length){
for(var scriptIndex in scripts) {
if(!alreadyLoaded && desiredSource === scripts[scriptIndex].src) {
alreadyLoaded = true;
}
}
}
if(!alreadyLoaded){
// Run your code in this block?
}
})();
As mentioned in the comments (https://stackoverflow.com/users/1358777/alwin-kesler), this may be an alternative (not benchmarked):
(function(){
var desiredSource = 'https://sitename.com/js/script.js';
var scripts = document.getElementsByTagName('script');
var alreadyLoaded = false;
for(var scriptIndex in document.scripts) {
if(!alreadyLoaded && desiredSource === scripts[scriptIndex].src) {
alreadyLoaded = true;
}
}
if(!alreadyLoaded){
// Run your code in this block?
}
})();
Simply check if the global variable is available, if not check again. In order to prevent the maximum callstack being exceeded set a 100ms timeout on the check:
function check_script_loaded(glob_var) {
if(typeof(glob_var) !== 'undefined') {
// do your thing
} else {
setTimeout(function() {
check_script_loaded(glob_var)
}, 100)
}
}
Another way to check an external script is loaded or not, you can use data function of jquery and store a validation flag. Example as :
if(!$("body").data("google-map"))
{
console.log("no js");
$.getScript("https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=initilize",function(){
$("body").data("google-map",true);
},function(){
alert("error while loading script");
});
}
}
else
{
console.log("js already loaded");
}
I think it's better to use window.addEventListener('error') to capture the script load error and try to load it again.
It's useful when we load scripts from a CDN server. If we can't load script from the CDN, we can load it from our server.
window.addEventListener('error', function(e) {
if (e.target.nodeName === 'SCRIPT') {
var scriptTag = document.createElement('script');
scriptTag.src = e.target.src.replace('https://static.cdn.com/', '/our-server/static/');
document.head.appendChild(scriptTag);
}
}, true);
Merging several answers from above into an easy to use function
function GetScriptIfNotLoaded(scriptLocationAndName)
{
var len = $('script[src*="' + scriptLocationAndName +'"]').length;
//script already loaded!
if (len > 0)
return;
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = scriptLocationAndName;
head.appendChild(script);
}
My idead is to listen the error log if there is an error on script loading.
const checkSegmentBlocked = (e) => {
if (e.target.nodeName === 'SCRIPT' && e.target.src.includes('analytics.min.js')) {
window.isSegmentBlocked = true;
e.target.removeEventListener(e.type, checkSegmentBlocked);
}
};
window.addEventListener('error', checkSegmentBlocked, true);
Some answers on this page are wrong. They check for the existence of the <script> tag - but that is not enough. That tells you that the tag was inserted into the DOM, not that the script is finished loading.
I assume from the question that there are two parts: the code that inserts the script, and the code that checks whether the script has loaded.
The code that dynamically inserts the script:
let tag = document.createElement('script');
tag.type = 'text/javascript';
tag.id = 'foo';
tag.src = 'https://cdn.example.com/foo.min.js';
tag.onload = () => tag.setAttribute('data-loaded', true); // magic sauce
document.body.appendChild(tag);
Some other code, that checks whether the script has loaded:
let script = document.getElementById('foo');
let isLoaded = script && script.getAttribute('data-loaded') === 'true';
console.log(isLoaded); // true
If the both of those things (inserting and checking) are in the same code block, then you could simplify the above:
tag.onload = () => console.log('loaded');
I found a quick tip before you start diving into code that might save a bit of time. Check devtools on the webpage and click on the network tab. The js scripts are shown if they are loaded as a 200 response from the server.

Categories