Geuis
Geuis

Reputation: 42267

javascript - get node reference to script tag that calls a function

How might one go about obtaining a reference to the DOM script tag that called a function?

For example:

<script type="text/javascript">
    var globalfunc = function(){
        //obtain a reference to the script block that globalfunc() was called from
    }
</script>

<script type="text/javascript">
    globalfunc();
</script>

I know that I could assign an id or class to the script element and pass that through to my function to do a DOM lookup, but I think it would be more flexible and elegant to do it without such a thing. The main reason is that I may have to do some work on our site to get 3rd party ads wrangled into shape, and we don't have control over the scripts they use to load their ads.

Upvotes: 3

Views: 2780

Answers (3)

Eli Grey
Eli Grey

Reputation: 35850

Here's my solution: It will work in every browser except IE, it requires that you catch a real error (well it doesn't for Firefox, but other browsers do), and you must call it from an external script (<script src="...">) to use it.

var getErrorScriptNode = (function () {
    var getErrorSource = 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+$/, "");
        }
        return loc;
    },
    anchor = document.createElement("a");

    return function (error) {
        anchor.href = getErrorSource(error);
        var src = anchor.href,
        scripts = document.getElementsByTagName("script");
        anchor.removeAttribute("href");
        for (var i = 0, l = scripts.length; i < l; i++) {
            anchor.href = scripts.item(i).src;
            if (anchor.href === src) {
                anchor.removeAttribute("href");
                return scripts.item(i);
            }
        }
    };
}());

Usage

var globalfunc = function (err) {
    var scriptNode = getErrorScriptNode(err);
    // ...
};

In an external (must be EXTERNAL) script that calls globalfunc():

try {
    0();
} catch (e) {
    var err = e;
}
// do stuff...
globalfunc(err);

Upvotes: 1

J5.
J5.

Reputation: 356

Assuming the script tag is not deferred, when the function executes, it should be from the last script tag in the page. So something like

var scripts = document.getElementsByTagName("script");
var scriptElement = scripts[scripts.length-1];

should get the reference.

You should wrap the original function in your own construct to insert this code, something like:

var old_global = globalFunction;
globalFunction = function () {
    var scripts = document.getElementsByTagName("script");
    var scriptElement = scripts[scripts.length-1];

    old_global.call(this,arguments);

    // do something after
};

This code is untested but may give you the idea.

Upvotes: 2

Justin Johnson
Justin Johnson

Reputation: 31300

Actually, you can't assign a class or id to a script element if you want to have valid markup. That said, I have used that method and yes it does work.

Alternatively, and let the record show that I would never do this, you could do something like:

var scripts = document.getElementsByTagName("script");

for (var i=0, l=scripts.length; i<l; ++i ) {
  if ( scripts[i].innerHTML.indexOf("globalfunc();") != -1 ) {
     // Found a script tag in which `globalfunc();` is executed
  }
}

Upvotes: 1

Related Questions