How to embed Javascript widget that depends on jQuery into an unknown environment
After reviewing some answers and pointers, and finding some helpful jQuery hackers, I ended up with something like the following:
(function(window, document, version, callback) { var j, d; var loaded = false; if (!(j = window.jQuery) || version > j.fn.jquery || callback(j, loaded)) { var script = document.createElement("script"); script.type = "text/javascript"; script.src = "/media/jquery.js"; script.onload = script.onreadystatechange = function() { if (!loaded && (!(d = this.readyState) || d == "loaded" || d == "complete")) { callback((j = window.jQuery).noConflict(1), loaded = true); j(script).remove(); } }; (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script); }})(window, document, "1.3", function($, jquery_loaded) { // Widget code here});
This will load jQuery if it's not already loaded and encapsulates it in the callback so it doesn't conflict with a pre-existing jQuery on the page. It also checks that a minimum version is available or else loads a known version -- in this case, v1.3. It sends a boolean value to the callback (my widget) on whether or not jQuery was loaded in case there are any triggers needed to be made. And only after jQuery is loaded does it call my widget, passing jQuery into it.
See How to build a web widget (using jQuery) by Alex Marandon.
(function() {// Localize jQuery variablevar jQuery;/******** Load jQuery if not present *********/if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.4.2') { var script_tag = document.createElement('script'); script_tag.setAttribute("type","text/javascript"); script_tag.setAttribute("src", "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"); if (script_tag.readyState) { script_tag.onreadystatechange = function () { // For old versions of IE if (this.readyState == 'complete' || this.readyState == 'loaded') { scriptLoadHandler(); } }; } else { // Other browsers script_tag.onload = scriptLoadHandler; } // Try to find the head, otherwise default to the documentElement (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);} else { // The jQuery version on the window is the one we want to use jQuery = window.jQuery; main();}/******** Called once jQuery has loaded ******/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(); }/******** Our main function ********/function main() { jQuery(document).ready(function($) { // We can use jQuery 1.4.2 here });}})(); // We call our anonymous function immediately
What if you also want to use some jQuery plugins? Is it safe to make yourself a single file with the minified versions of the plugins, and also load those, as below? (Loaded from S3, in this particular example.)
(function(window, document, version, callback) { var j, d; var loaded = false; if (!(j = window.jQuery) || version > j.fn.jquery || callback(j, loaded)) { var script = document.createElement("script"); script.type = "text/javascript"; script.src = "http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"; script.onload = script.onreadystatechange = function() { if (!loaded && (!(d = this.readyState) || d == "loaded" || d == "complete")) { window.jQuery.getScript('http://mydomain.s3.amazonaws.com/assets/jquery-plugins.js', function() { callback((j = window.jQuery).noConflict(1), loaded = true); j(script).remove(); }); } }; document.documentElement.childNodes[0].appendChild(script) }})(window, document, "1.5.2", function($, jquery_loaded) { // widget code goes here});