16

How can I get the path of the current script in javascript using jQuery

for example I have site.com/js/script.js and there is a code in this script:

$(document).ready(function() {
   alert(  ... this code ... );
}

It Should return alert box with the "/js/script.js" message. This function should work like magic __FILE__ constant in php

So, why do I need this?

I want to set background image dynamically:

$("somediv").css("background-image", "url(" + $SCRIPT_PATH + "/images/img.png)");

and images directory is the /js directory, near the script.js file

and js folder's name can be dynamically set, so script and images can be in the /myprogect/javascript-files directory

John Slegers
  • 45,213
  • 22
  • 199
  • 169
pleerock
  • 18,322
  • 16
  • 103
  • 128
  • 1
    What about pass your javascript code files through a PHP parser(as usually done with ".php" files) and do something like `alert('= __FILE__ ?>');`? (I know that by this approach you will need to avoid stray ` ... ?>` and stuff in the files) – Prusse Dec 15 '11 at 16:39
  • Just use a relative path like `$("somediv").css("background-image", "url(./images/img.png)");`. – Prusse Dec 15 '11 at 16:45
  • I can't run php code inside my .js files and I don't want change server configuration (cos it also will run on user servers) – pleerock Dec 15 '11 at 16:49
  • I already have tried relative path "./" and also "../", "./../" (for the test). But it isn't working. It seems browser automatically override this path to "http://site.com/images/img.png" – pleerock Dec 15 '11 at 16:53
  • the code that set the folder dynamically should set an option (in a global variable for exemple) accessible from your javascript code – Guillaume86 Dec 15 '11 at 17:23
  • A relative path seem to work http://jsfiddle.net/mTQHx/ – Prusse Dec 15 '11 at 17:33
  • works? Browser returns me "diva background-image: url("http://fiddle.jshell.net/_display/images/smile.png")" (site address included) – pleerock Dec 15 '11 at 17:55
  • See the result when you firstly get to the page, the 'run' button in jsfiddle causes a different behavior. – Prusse Dec 16 '11 at 13:01
  • possible duplicate of [How might I get the script filename from within that script?](http://stackoverflow.com/questions/710957/how-might-i-get-the-script-filename-from-within-that-script) – Bergi Jul 17 '13 at 15:42
  • here: http://stackoverflow.com/questions/2161159/get-script-path – Chaki_Black Nov 18 '14 at 16:29

4 Answers4

27

You can rely on the fact that each <script> element has to be evaluated* before the next one is inserted into the DOM.

This means that the script currently evaluated (as long as it is part of your markup and not dynamically inserted) will be the last one in the NodeList retrieved with getElementsByTagName( 'script' ).

This allows you to read that elements src attribute and from that determine the folder that the script is being served from - like this:

var scriptEls = document.getElementsByTagName( 'script' );
var thisScriptEl = scriptEls[scriptEls.length - 1];
var scriptPath = thisScriptEl.src;
var scriptFolder = scriptPath.substr(0, scriptPath.lastIndexOf( '/' )+1 );

console.log( [scriptPath, scriptFolder] );

I tried this technique with 3 scripts loaded from different folders and get this output

/*
["http://127.0.0.1:8000/dfhdfh/folder1/script1.js", "http://127.0.0.1:8000/dfhdfh/folder1/"]
["http://127.0.0.1:8000/dfhdfh/folder2/script2.js", "http://127.0.0.1:8000/dfhdfh/folder2/"]
["http://127.0.0.1:8000/dfhdfh/folder3/script3.js", "http://127.0.0.1:8000/dfhdfh/folder3/"]
*/

* from John Resigs blog linked to above

This means that when the script finally executes that it'll be the last script in the DOM - and even the last element in the DOM (the rest of the DOM is built incrementally as it hits more script tags, or until the end of the document).

Update

As pimvdb points out - this will work as the script is being evaluated. You will need to store the path somehow if you are going to use it later. You can't query the DOM at a later point. If you use the same snippet for each script the value of scriptFolder will be overwritten for each script. You should give each script a unique variable perhaps?

Wrapping your script in its own scope closes over the value of scriptFolder making it available to the rest of the script without fear of being overwritten

(function() {

    var scriptEls = document.getElementsByTagName( 'script' );
    var thisScriptEl = scriptEls[scriptEls.length - 1];
    var scriptPath = thisScriptEl.src;
    var scriptFolder = scriptPath.substr(0, scriptPath.lastIndexOf( '/' )+1 );


    $( function(){
        $('#my-div').click(function(e){
            alert(scriptFolder);
        });
    });


})();
Gordon
  • 19,811
  • 4
  • 36
  • 74
meouw
  • 41,754
  • 10
  • 52
  • 69
  • Is it correct that this will only give correct results when evaluated directly? I think that only then the last script element is the one of the executing file. – pimvdb Dec 15 '11 at 17:06
  • 1
    Yeah, I have already think about such method. But... Imagine if another programmer will add an another script in the head of the document (which is maybe used some functions of our script, or maybe he doesn't know that he shouldn't add extra scripts). in this case it makes another programmer's life bothering( – pleerock Dec 15 '11 at 18:02
  • 2
    You CAN NOT rely on the scripts being loaded from script tags. – catbadger Jul 07 '16 at 15:37
9

Add the following code to your JS :

var retrieveURL = function(filename) {
    var scripts = document.getElementsByTagName('script');
    if (scripts && scripts.length > 0) {
        for (var i in scripts) {
            if (scripts[i].src && scripts[i].src.match(new RegExp(filename+'\\.js$'))) {
                return scripts[i].src.replace(new RegExp('(.*)'+filename+'\\.js$'), '$1');
            }
        }
    }
};

Suppose these are the scripts called in your HTML :

<script src="assets/js/awesome.js"></script>
<script src="assets/js/oldcode/fancy-stuff.js"></script>
<script src="assets/js/jquery/cool-plugin.js"></script>

Then, you can use the function like this

var awesomeURL = retrieveURL('awesome');
// result : 'assets/js/'

var awesomeURL = retrieveURL('fancy-stuff');
// result : 'assets/js/oldcode/'

var awesomeURL = retrieveURL('cool-plugin');
// result : 'assets/js/jquery/'

Note that this only works when there are no two script files in your HTML with the same name. If you have two scripts with the same name that are located in a different folder, the result will be unreliable.


Note

If you dynamically add scripts to your page, you need to make sure your code is executed after the last script has been added to the DOM.

The follow example shows how to do this with one dynamically loaded script. It outputs a JSON array with the src link for scripts that load an external js file and a base64-encoded string of the JS content for inline scripts:

var addScript = function(src, callback) {
    var s = document.createElement( 'script' );
    s.setAttribute( 'src', src );
    document.body.appendChild( s );
    s.onload = callback;
}

var retrieveURL = function(filename) {
    var scripts = document.getElementsByTagName('script');
    if (scripts && scripts.length > 0) {
        for (var i in scripts) {
            if (scripts[i].src && scripts[i].src.match(new RegExp(filename+'\\.js$'))) {
                return scripts[i].src.replace(new RegExp('(.*)'+filename+'\\.js$'), '$1');
            }
        }
    }
};

addScript('https://code.jquery.com/jquery-1.12.4.min.js', function() {
    var scripts = document.getElementsByTagName('script');
    var sources = [];
    for (var i = 0; i < scripts.length; i++) {
        if(scripts[i].src == '') {
            sources.push(btoa(scripts[i].innerHTML));
        } else {
            sources.push(scripts[i].src);
        }
    }
    document.body.innerHTML += '<pre>' + JSON.stringify(sources,null,2) + '</pre>';
});

See also this Fiddle.

Community
  • 1
  • 1
John Slegers
  • 45,213
  • 22
  • 199
  • 169
  • this is useless if the script is loaded dynamically. – catbadger Jul 07 '16 at 15:36
  • @catbadger : Dynamically loaded scripts are still added to the DOM, so this should work with dynamically loaded scripts as well. Just make sure you execute the function AFTER the dynamically loaded scripts have been loaded. See the demo code I just added for how to do this with one dynamically loaded script. – John Slegers Jul 08 '16 at 08:05
1

I don't think jQuery provide such a functionality. Anyway you can get currentc script path path (both fully http and relative) by reading the answer here: What is my script src URL?

Community
  • 1
  • 1
Marco Demaio
  • 33,578
  • 33
  • 128
  • 159
0

Can't you set a kind of path variable in the js? So, you save the path of the file in the file itself. For example:

$(function() {
  var FilePath = "js/some/path";
  setMyDynamicImageUsingPath(FilePath);
});

// ...

function setMyDynamicImageUsingPath(path) {
  $("somediv").css("background-image", "url(" + path + "/images/img.png)");
}
grilix
  • 5,211
  • 5
  • 33
  • 34