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

10
  • 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) Commented Dec 15, 2011 at 16:39
  • Just use a relative path like $("somediv").css("background-image", "url(./images/img.png)");. Commented Dec 15, 2011 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) Commented Dec 15, 2011 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 "site.com/images/img.png" Commented Dec 15, 2011 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 Commented Dec 15, 2011 at 17:23

4 Answers 4

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);
        });
    });


})();
Sign up to request clarification or add additional context in comments.

3 Comments

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.
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(
You CAN NOT rely on the scripts being loaded from script tags.
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.

2 Comments

this is useless if the script is loaded dynamically.
@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.
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?

Comments

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)");
}

1 Comment

unfortunately I can't. Path name is dynamic, so I can't every time change fixed variable value

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.