5

I need to load cross-domain JavaScript
files dynamically for bookmarklets in my site http://jsbookmarklets.com/


The solution should satisfy:

  • Fetch the path of current file
  • The domain of current web-page and JS file in execution are different
  • The solution should be cross-browser
  • Multiple scripts might be loaded at once asynchronously (that's why the related questions mentioned below are not a fit)


I want to get the file path of currently executing JavaScript code for dynamically loading few more resources (more CSS files and JS files like custom code and jQuery, jQuery UI and Ext JS libraries) which are stored in the same/relative folder as the JavaScript Bookmarklet.


The following approach does not fit my problem:

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


Related questions which do not fit my problem:

Community
  • 1
  • 1
  • I don't see why the first related question does not answer yours. And please show us *how* you are dynamically loading scripts, it is substantial for getting the path. – Bergi Jan 01 '13 at 13:45
  • The mentioned approach does not work for cross-domain JS files – webextensions.org Jan 01 '13 at 14:00
  • Only the first sentence is relevant: It does not work in general, but there may be workarounds. However, you could just put a static variable for your path in your script that might be generated by a serverside script. – Bergi Jan 01 '13 at 14:04
  • I am loading new JavaScript files using var s = document.createElement('script'); s.setAttribute('src', 'code.js'); document.body.appendChild(s); And I believe this is the only way possible for cross-domain files (modern cross-domain AJAX (like) requests are not an option since I need a generic solution which works on almost any random website) – webextensions.org Jan 01 '13 at 14:06
  • My code needs to run on any random website since it is a bookmarklet. I do have a partial solution (I'll add that if I don't get any better ones) ... my code needs long codes, involves throwing error and handling timeouts and the code goes too specific/complicated ... blah blah – webextensions.org Jan 01 '13 at 14:10
  • not really clear what your underlying problem really is. Seems like if you have path info to create script tag, would be trivial to add as variable or argument of functions within code – charlietfl Jan 01 '13 at 15:08
  • I have posted my current approach (as an answer) I had mentioned that I was using timeout in my current approach ... I realize that I'm not! – webextensions.org Jan 06 '13 at 21:22
  • I do not understand the use cases you are generating that require such a convoluted solution, as the one described in your answer. Please offer more information on what it is you are trying to achieve, why (considering we might offer you alternatives) and how you're currently facing the issue... – Khez Jan 09 '13 at 03:10
  • 2
    why not simply generate some part of your js file on server-side, smthg like `var __domain = '$_HOST';` ? this will work in any browser, down to netscape. – c69 Jan 09 '13 at 21:36
  • @c9 Generating part of code server-side ... an overkill but yes an interesting approach ... – webextensions.org Jan 13 '13 at 19:56

3 Answers3

4

The current solution that I'm using, which works, but is very lengthy:

var fnFullFilePathToFileParentPath = function(JSFullFilePath){
    var JSFileParentPath = '';
    if(JSFullFilePath) {
        JSFileParentPath = JSFullFilePath.substring(0,JSFullFilePath.lastIndexOf('/')+1);
    } else {
        JSFileParentPath = null;
    }
    return JSFileParentPath;
};

var fnExceptionToFullFilePath = function(e){
    var JSFullFilePath = '';

    if(e.fileName) {    // firefox
        JSFullFilePath = e.fileName;
    } else if (e.stacktrace) {  // opera
        var tempStackTrace = e.stacktrace;
        tempStackTrace = tempStackTrace.substr(tempStackTrace.indexOf('http'));
        tempStackTrace = tempStackTrace.substr(0,tempStackTrace.indexOf('Dummy Exception'));
        tempStackTrace = tempStackTrace.substr(0,tempStackTrace.lastIndexOf(':'));
        JSFullFilePath = tempStackTrace;
    } else if (e.stack) {   // firefox, opera, chrome
        (function(){
            var str = e.stack;
            var tempStr = str;

            var strProtocolSeparator = '://';
            var idxProtocolSeparator = tempStr.indexOf(strProtocolSeparator)+strProtocolSeparator.length;

            var tempStr = tempStr.substr(idxProtocolSeparator);
            if(tempStr.charAt(0)=='/') {
                tempStr = tempStr.substr(1);
                idxProtocolSeparator++;
            }

            var idxHostSeparator = tempStr.indexOf('/');
            tempStr = tempStr.substr(tempStr.indexOf('/'));

            var idxFileNameEndSeparator = tempStr.indexOf(':');
            var finalStr = (str.substr(0,idxProtocolSeparator + idxHostSeparator + idxFileNameEndSeparator));
            finalStr = finalStr.substr(finalStr.indexOf('http'));
            JSFullFilePath = finalStr;
        }());
    } else {    // internet explorer
        JSFullFilePath = null;
    }

    return JSFullFilePath;
};

var fnExceptionToFileParentPath = function(e){
    return fnFullFilePathToFileParentPath(fnExceptionToFullFilePath(e));
};

var fnGetJSFileParentPath = function() {
    try {
        throw new Error('Dummy Exception');
    } catch (e) {
        return fnExceptionToFileParentPath(e);
    }
};

var JSFileParentPath = fnGetJSFileParentPath();
alert('File parent path: ' + JSFileParentPath);
  • I'm expecting a better answer than the currently posted one because the current answer involves error handling which causes inability to use it along with debugging in IE. – webextensions.org Jan 06 '13 at 21:30
  • Going with my original solution as mentioned in this answer ... there is no perfect solution and the other answers might be more easy to implement depending on the requirement. – webextensions.org Mar 01 '13 at 14:30
1
var s = document.createElement('script'); 
s.setAttribute('src', 'code.js'); 
document.body.appendChild(s);

Can you not simply do this?

var myScriptDir = 'http://somesite.tld/path-to-stuff/';
var s = document.createElement('script'); 
s.setAttribute('src', myScriptDir + 'code.js'); 
document.body.appendChild(s); 
// code inside http://somesite.tld/path-to-stuff/code.js will use myScriptDir to load futher resources from the same directory.

If you don't want to have code inside the script to be responsible for loading further resources you can use the onload attribute of the script tag, like s.onload=function(){...}. For cross browser compatibility you might first load jQuery and then use the getScript function. Relevant links are http://www.learningjquery.com/2009/04/better-stronger-safer-jquerify-bookmarklet and http://api.jquery.com/jQuery.getScript/

DG.
  • 3,417
  • 2
  • 23
  • 28
0

Some of the comments have already mentioned this, but I'll try to elaborate a bit more.

The simplest, most cross-browser, cross-domain way of figuring out the path of the current script is to hard-code the script's path into the script itself.

In general, you may be loading third-party script files, so this would not be possible. But in your case, all the script files are under your control. You're already adding code to load resources (CSS, JS, etc.), you might as well include the script path as well.

Jeffery To
  • 11,836
  • 1
  • 27
  • 42
  • The problem with this approach is of maintenance when you wish to move the file around ... it seems there is no ideal solution for what I wanted. – webextensions.org Jan 13 '13 at 19:52
  • Yes, maintenance is an issue, but you can generate your scripts server-side (as @c9 suggests) or use [Grunt](http://gruntjs.com/) or a similar tool to (re-)generate your scripts if/when you move them. The point is, finding the path of the current script is not work that needs to be done on the browser. Moving your scripts is a future possibility; the inability to debug in IE is a real problem right now. – Jeffery To Jan 14 '13 at 01:13