Normally I have used the following code snippet, and this usually works:
(function () {
function main() {
//...script body...
}
var OGloboCSS = { // var could be named anything, appropriate to the page
addJQuery: function (callback) {
var script = document.createElement("script");
script.setAttribute("src", "https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js");
script.addEventListener('load', function () {
var script = document.createElement("script");
script.textContent = "window.jQ=jQuery.noConflict(true);(" + callback.toString() + ")();";
document.body.appendChild(script);
}, false);
document.body.appendChild(script);
}
};
OGloboCSS.addJQuery(main);
})();
But occasionally I get an error like this one on https://steamcommunity.com:
Refused to load the script 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js' because it violates the following Content Security Policy directive: "script-src 'unsafe-eval' 'self' 'unsafe-inline' 'unsafe-eval' https://steamcommunity-a.akamaihd.net/ https://api.steampowered.com/ http://www.google-analytics.com https://ssl.google-analytics.com https://www.google.com https://www.gstatic.com https://apis.google.com".
And the solution is basically, you have to use TamperMonkey's @require
header directive instead, something like this:
// @require https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js
// ==/UserScript==
window.jQ = $;
(function () {
/*this used to be: function main() */
//...same script body, without container function...
})();
And this works just fine, but it doesn't safely load jQuery to the jQ
variable, it clobbers $
. Is it really a problem? Yes, you can see that in how pagination breaks in steamcommunity.com's discussion threads.
Is there some way to @require jQ=
and then @grant jQ
- still giving me jQ
both in the Tampermonkey script and the console, without clobbering in-page variables?
This way the confirmation dialog can be avoided for most of the users. Additionally add "@connect *" to the script. By doing so Tampermonkey will still ask the user whether the next connection to a not mentioned domain is allowed, but also offer a "Always allow all domains" button .
· Issue #979 · Tampermonkey/tampermonkey · GitHub 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.
---> scriptSource: "// ==UserScript== // @name Local File Test ...." <><! [CDATA [your_text_here]]></> Tampermonkey supports this way of storing meta data.
By doing so Tampermonkey will still ask the user whether the next connection to a not mentioned domain is allowed, but also offer a "Always allow all domains" button . If the user clicks at this button then all future requests will be permitted automatically. both, the initial and the final URL will be checked!
Apart from avoiding version conflicts and breaking the content page, I do a handful of other things in my default userscript template that includes jQuery.
The template below strives to meet the following goals in the interest of being a universal template for including jQuery in new scripts regardless of the content page's current or future status with regards to it's own inclusion, or lack thereof, of jQuery of any version.
The use of @grant none is key here
//@grant none
@grant none works for 99% of my scripts. It allows easy access to the content page's variables, functions, and objects by maintaining a global scope for the UserScript(this), and providing unqualified access to the content page's global scope(window) by searching both scopes for variable, function identifiers in this, window order. So if you avoid duplicating identifiers that exist in the content page, you can access content page variables, functions, and function return values without qualifying ("this." or "window."). And you can do so from anywhere in your script.
This highlights the OP's orignal issue. The convenience that @grant none provides is also the reason the @require directive overwrites the window's $ and jQuery references when it loads. The jQuery library has included the noConflict() function for quite some time to handle just this issue.
We can do some quick improvements right away to the answer above to increase our safety/compatibility/reuse.
window.jQ = $.noConflict(true);
This code instead
this.$ = window.jQuery.noConflict(true);
That last point is probably overkill, but why not be explicit and use the jQuery identifier to make the noConflict call. While it would be our fault at this point if $ wasn't jQuery when this call runs (@require for another library that uses $, using it yourself before this code runs, etc,) it's free prevention of later debugging effort.
While we could be done and happy there, we can also go a bit further to ensure compatibility across the widest variety of pages, and through the largest variety of content page changes.
(function ($, undefined) {
$(function () {
//Your code here;
});
})(window.jQuery.noConflict(true));
While still not guaranteed, this pattern gives your functional code the best chance to execute in the largest variety of page lifecyle possibilities by keeping the $ alias out of the global scope and leveraging jQuery's DOM Ready event to ensure page completion. As an aside it also ensures a consistent undefined value for your code.
// ==UserScript==
// @name jQuery safe inclusion template
// @description include jQuery and make sure window.$ is the content page's jQuery version, and this.$ is our jQuery version.
// @version 0.0.1
// @author Sonic Beard
// @match http://*.site.com/*
// @require http://cdn.jsdelivr.net/jquery/2.1.3/jquery.min.js
// @grant none
// ==/UserScript==
(function ($, undefined) {
$(function () {
//Your code here;
});
})(window.jQuery.noConflict(true));
TamperMonkey does not appear to have such functionality, but an alternative would be to immediately call $.noConflict
with the removeAll
argument set to true
. This will cause jQuery to reset the original $
and jQuery
back to their original values.
// ==UserScript==
// @name jQuery noConflict test
// @namespace http://example.com/
// @version 0.1
// @description test jQuery noConflict
// @author You
// @match https://steamcommunity.com/
// @require https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js
// @grant none
// ==/UserScript==
window.jQ = $.noConflict(true);
And you can see from the example console input below, jQ
is the jQuery 2.1.3 that was loaded by @require
, jQuery
is the version of jQuery the page loads, and $
is still the original prototype library object, as evidenced by not having jQuery's fn
property.
> jQ.fn.jquery
< "2.1.3"
> jQuery.fn.jquery
< "1.11.1"
> $.fn
< undefined
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