10

So I'm trying to load a script dynamically and figure out the URL path at which that script was loaded. So some guy gave me a pretty awesome solution to this problem if the scripts are statically loaded ( How to get the file-path of the currently executing javascript code ). But I need a dynamically loaded solution. For example:

$(function()
{   $.getScript("brilliant.js", function(data, textStatus)
    {   // do nothing   
    });
});

where "brilliant.js" has:

var scripts = document.getElementsByTagName("script");
var src = scripts[scripts.length-1].src;
alert("THIS IS: "+src);

Ideally this should either print out "brilliant.js" or "〈hostname+basepath〉/brilliant.js"

Currently brilliant.js works for statically included scripts, but not for scripts included dynamically (like with $.getScript). Anyone have any ideas? Is there somewhere in the dom that stores all the scripts that have been loaded?

EDIT: Andras gave a pretty good solution, though it probably only works for jQuery. Since that's probably the most popular library, and definitely what I'm going to be using. It can probably be extended for other libraries as well. Here's my simplified version:

var scriptUri;
curScriptUrl(function(x)
{   scriptUri = x;
    alert(scriptUri);
});

function curScriptUrl(callback)
{   var scripts = document.getElementsByTagName("script");
    var scriptURI = scripts[scripts.length-1].src;  

    if(scriptURI != "")         // static include
    {   callback(scriptURI);
    }else if($ != undefined)    // jQuery ajax
    {   $(document).ajaxSuccess(function(e, xhr, s)
        {   callback(s.url);
        }); 
    }
}
Community
  • 1
  • 1
B T
  • 57,525
  • 34
  • 189
  • 207
  • I like what chamiltongt (below) said, ajax in the code, and then eval() it. To make it universally accessible, why not set up a microsite serving up your .js code. It would be centralised and you're able to update your code for every user instantaneously. – logout Feb 21 '10 at 22:23

3 Answers3

8

When your script gets loaded with jQuery (and I guess other frameworks as well), your script will become indistinguishable from a script that was originally in the HTML document.

jQuery makes a request reaching out for your script and puts back the reply as the text child of a <script> node. Your browser has no way of knowing where it originated from, whether it was modified before inserted, etc. It is just a script node as far as she is concerned.

There can be workarounds, however. In the case of jQuery, you can hook up to the ajax events and exploit the fact that they are called right after your script executes. Basically, this would yield "brilliant.js" in your example:

var handler = function (e, xhr, s) {
    alert(s.url);
}

$(document).ajaxSuccess(handler);

A more elaborate one:

(function ($, undefined) {

    /* Let's try to figure out if we are inlined.*/
    var scripts = document.getElementsByTagName("script");

    if (scripts[scripts.length - 1].src.length === 0) {
        // Yes, we are inlined.
        // See if we have jQuery loading us with AJAX here. 
        if ($ !== undefined) {
            var initialized = false;
            var ajaxHandler = function (e, xhr, s) {
                if (!initialized) {
                    initialized = true;
                    alert("Inlined:" + s.url);
                    initmywholejsframework();
                }
            }

            //If it is, our handler will be called right after this file gets loaded.
            $(document).ajaxSuccess(ajaxHandler);

            //Make sure to remove our handler if we ever yield back.
            window.setTimeout(function () {
                jQuery(document).unbind("ajaxSuccess", ajaxHandler);
                if (!initialized) {
                    handleInlinedNonjQuery();
                }
            }, 0);

        }
    } else {
        //We are included.
        alert("Included:" + scripts[scripts.length - 1].src);
        initmywholejsframework();
    }

    //Handle other JS frameworks etc. here, if you will.
    function handleInlinedNonjQuery() {
        alert("nonJQuery");
        initmywholejsframework();
    }

    //Initialize your lib here
    function initmywholejsframework() {
        alert("loaded");
    }

})(jQuery);
Andras Vass
  • 11,478
  • 1
  • 37
  • 49
  • Cool workaround. I wish a more universal way to solve this existed - but it looks like this is just about the best there is. I edited my question above to show my version of what you wrote. – B T Feb 22 '10 at 19:51
-1

B T, sorry if this doesn't help, but I'm curious why you would need to do this? The reason I'm asking is I don't see why you can't just use the relative file paths to load these files? Finding out where you're located could be done with window.location, but why would you? And as for loading them, can't you make an ajax call to the file and then eval them?

chamiltongt
  • 152
  • 3
  • Also, I just remembered an easier way, you can add script elements to the page dynamically. Below is a link to how to do this -> http://www.codehouse.com/javascript/articles/external/ – chamiltongt Feb 17 '10 at 04:06
  • I'm making a javascript library meant to be loaded by external domains. This isn't a question about simple javascript files. See the following link if you want to have more context, thanks: http://stackoverflow.com/questions/2255689/how-to-get-the-file-path-of-the-currenctly-executing-javascript-code . – B T Feb 17 '10 at 20:10
-1

This will work in every browser except IE and doesn't depend on assuming what the name of a file is:

var getErrorLocation = function (error) {
    var loc, replacer = function (stack, matchedLoc) {
        loc = matchedLoc;
    };

    if ("fileName" in error) {
        loc = error.fileName;
    } else if ("stacktrace" in error) { // Opera
        error.stacktrace.replace(/Line \d+ of .+ script (.*)/gm, replacer);
    } else if ("stack" in error) { // WebKit
        error.stack.replace(/at (.*)/gm, replacer);
        loc = loc.replace(/:\d+:\d+$/, ""); // remove line number
    }
    return loc;
};

try {
    0();
} catch (e) {
    var scriptURI = getErrorLocation(e);
}

alert("THIS IS: " + scriptURI);
Eli Grey
  • 35,104
  • 14
  • 75
  • 93
  • He is loading the script with $.getScript() which is equivalent to appending a – Andras Vass Feb 21 '10 at 22:30