Is any way to get the file info (file name, path) of a javascript file after the document is ready, without knowing how many scripts or the order how they are loaded?
i.e.
<html>
<head>
<script src="http://www.example.ex/js/js1.js" type="text/javascript">
<script src="http://www.example.ex/javascript/js2.js" type="text/javascript">
<script src="http://www.example.ex/scripts/js3.js" type="text/javascript">
<...>
Where the file js2.js has something like this:
$(document).ready(function() {
// get the filename "js2.js"
}
I could do
var scripts = document.getElementsByTagName("script"),
scriptLocation = scripts[1].src;
but the index "[1]" must be dynamic because i don't know the order of the loaded scripts.
Perhaps a full answer would be more helpful than my comments. If you put this code into js2.js, you'll get what you want. The key is to capture scriptLocation in a piece of code which runs synchronously with the loading the file, which means not in a callback.
var scripts = document.getElementsByTagName("script"),
scriptLocation = scripts[scripts.length - 1].src;
$(document).ready(function() {
// logs the full path corresponding to "js2.js"
console.log(scriptLocation);
}
To get Line Number and filename from Error.stack eg:
console.log((new Error).stack.split("\n"));
See Error.stack
For browser compatibility, see previous SO question
Not entirely sure what you're after, but if you want to get reference to all the scripts loaded in the DOM, you would simply do:
var scripts = document.getElementsByTagName("script");
for(var i = 0; i < scripts.length; i++){
var scriptLocation = scripts[i].src;
}
var scripts = document.getElementsByTagName("script");
for (var i = 0; i < scripts.length; i++) {
if (scripts[i].src.match(/<desired filename>/) {
scriptLocation = scripts[i];
}
}
If I correctly understood your question, that should do the trick.
var scriptName = [].slice.call(document.getElementsByTagName('script')).pop().getAttribute('src');
document.getElementsByTagName('script') return HTMLCollection of page scripts. Last element is current script. HTMLCollection doesn't have method to get last, but after convert colliection by [].slice.call to Array we can call pop to do it. Finally getAttribute return desired filename.
Same code can used to passing arguments to js-script
<script src="file.js" args="arg1;arg2">
...
var args = [].slice.call(document.getElementsByTagName('script')).pop().getAttribute('args').split(';');
Related
I have 1 page that load Js file from another server. Its load file for each product in e-commerce store with its id in url see below structure.
Product 1:
http://static.www.xxx.com/mydata/uXKojYEd9WXFpAasite/v4_3/1/d/itemjs
Product 2:
http://static.www.xxx.com/mydata/uXKojYEd9WXFpAasite/v4_3/2/d/itemjs
Product 3:
http://static.www.xxx.com/mydata/uXKojYEd9WXFpAasite/v4_3/3/d/itemjs
All Js files contain code like below
var MyItemData={"counts":{"q":1,"a":1,"r":2,"ar":4,"rr":0,"dq":1,"da":1,"c":0,"sdsd":0},"active":true};
Now I am reading this data in Html like below
var mycounta = MyItemData.counts.a;
var mycountq = MyItemData.counts.q;
var mycountr = MyItemData.counts.r;
The problem here is I can only get data for last product as variable MyItemData is the same for all files. I've to read each files by id but i don't know proper way to achieve it. does anyone tried something like this?
You can loop the answer below which loads external js file dynamically.
How do I load a javascript file dynamically?
On each iteration, read MyItemData and use it.
By using the function loadJS on above link;
<script type="application/javascript">
var listOfJSFiles=["http://static.www.xxx.com/mydata/uXKojYEd9WXFpAasite/v4_3/1/d/itemjs", "http://static.www.xxx.com/mydata/uXKojYEd9WXFpAasite/v4_3/2/d/itemjs", "http://static.www.xxx.com/mydata/uXKojYEd9WXFpAasite/v4_3/3/d/itemjs"];
var listOfMyItemData=[];
function loadJS(file) {
// DOM: Create the script element
var jsElm = document.createElement("script");
// set the type attribute
jsElm.type = "application/javascript";
// make the script element load file
jsElm.src = file;
// finally insert the element to the body element in order to load the script
document.body.appendChild(jsElm);
}
var arrayLength = listOfJSFiles.length;
for (var i = 0; i < arrayLength; i++) {
loadJS(listOfJSFiles[i]);
listOfMyItemData.push(MyItemData);
//removing listOfJSFiles[i] from html is recommended.
}
</script>
Provided that you are loading those files using script tag. You could create an array to hold items and intermix script tags with inline scripts that save current value of MyItemData inside the array.
<script>
var items = [],
addItem = function() {
items.push(MyItemData)
};
</script>
Then call addItem after each script or play with onload event (not sure if the later would work).
<script
src="http://static.www.xxx.com/mydata/uXKojYEd9WXFpAasite/v4_3/1/d/itemjs"
>
</script>
<script>addItem()</script>
<script
src="http://static.www.xxx.com/mydata/uXKojYEd9WXFpAasite/v4_3/2/d/itemjs"
>
</script>
<script>addItem()</script>
etc.
In my HTML file I have linked to the JS with:
src="myscript.js?config=true"
Can my JS directly read the value of this var like this?
alert (config);
This does not work, and the FireFox Error Console says "config is not defined". How do I read the vars passed via the src attribute in the JS file? Is it this simple?
<script>
var config=true;
</script>
<script src="myscript.js"></script>
You can't pass variables to JS the way you tried. SCRIPT tag does not create a Window object (which has a query string), and it is not server side code.
Yes, you can, but you need to know the exact script file name in the script :
var libFileName = 'myscript.js',
scripts = document.head.getElementsByTagName("script"),
i, j, src, parts, basePath, options = {};
for (i = 0; i < scripts.length; i++) {
src = scripts[i].src;
if (src.indexOf(libFileName) != -1) {
parts = src.split('?');
basePath = parts[0].replace(libFileName, '');
if (parts[1]) {
var opt = parts[1].split('&');
for (j = opt.length-1; j >= 0; --j) {
var pair = opt[j].split('=');
options[pair[0]] = pair[1];
}
}
break;
}
}
You have now an 'options' variable which has the arguments passed. I didn't test it, I changed it a little from http://code.google.com/p/canvas-text/source/browse/trunk/canvas.text.js where it works.
You might have seen this done, but really the JS file is being preprocessed server side using PHP or some other language first. The server side code will print/echo the javascript with the variables set. I've seen a scripted ad service do this before, and it made me look into seeing if it can be done with plain ol' js, but it can't.
You need to use Javascript to find the src attribute of the script and parse the variables after the '?'. Using the Prototype.js framework, it looks something like this:
var js = /myscript\.js(\?.*)?$/; // regex to match .js
var jsfile = $$('head script[src]').findAll(function(s) {
return s.src.match(js);
}).each(function(s) {
var path = s.src.replace(js, ''),
includes = s.src.match(/\?.*([a-z,]*)/);
config = (includes ? includes[1].split('=');
alert(config[1]); // should alert "true" ??
});
My Javascript/RegEx skills are rusty, but that's the general idea. Ripped straight from the scriptaculous.js file!
Your script can however locate its own script node and examine the src attribute and extract whatever information you like.
var scripts = document.getElementsByTagName ('script');
for (var s, i = scripts.length; i && (s = scripts[--i]);) {
if ((s = s.getAttribute ('src')) && (s = s.match (/^(.*)myscript.js(\?\s*(.+))?\s*/))) {
alert ("Parameter string : '" + s[3] + "'");
break;
}
}
Whether or not this SHOULD be done, is a fair question, but if you want to do it, http://feather.elektrum.org/book/src.html really shows how. Assuming your browser blocks when rendering script tags (currently true, but may not be future proof), the script in question is always the last script on the page up to that point.
Then using some framework and plugin like jQuery and http://plugins.jquery.com/project/parseQuery this becomes pretty trivial. Surprised there's not a plugin for it yet.
Somewhat related is John Resig's degrading script tags, but that runs code AFTER the external script, not as part of the initialization: http://ejohn.org/blog/degrading-script-tags/
Credits: Passing parameters to JavaScript files , Passing parameters to JavaScript files
Using global variables is not a so clean or safe solution, instead you can use the data-X attributes, it is cleaner and safer:
<script type="text/javascript" data-parameter_1="value_1" ... src="/js/myfile.js"></script>
From myfile.js you can access the data parameters, for instance with jQuery:
var parameter1 = $('script[src*="myfile.js"]').data('parameter_1');
Obviously "myfile.is" and "parameter_1" have to match in the 2 sources ;)
You can do that with a single line code:
new URL($('script').filter((a, b, c) => b.src.includes('myScript.js'))[0].src).searchParams.get("config")
It's simpler if you pass arguments without names, just like function calls.
In HTML:
<script src="abc.js" data-args="a,b"></script>
Then, in JavaScript:
const args=document.currentScript.dataset.args.split(',');
Now args contains the array ['a','b'].
My HTML block as follows,
<html>
<title>Example</title>
<head>
</head>
<body>
<h2>Profile Photo</h2>
<div id="photo-container">Photo will load here</div>
<script type='text/javascript' src='http://example.com/js/coverphoto.js?name=johndoe'></script>
</body>
</html>
and I have saved this file as test.html. In JavaScript source the name will be dynamic.
I want to collect the name in coverphoto.js. Tried in coverphoto.js as,
window.location.href.slice(window.location.href.indexOf('?') + 1).split('&')
but it is getting the html file name (test.html) only. How can I retrieve the name key from http://example.com/js/coverphoto.js?name=johndoe in coverphoto.js?
To get the URL of the current JavaScript file you can use the fact that it will be the last <script> element currently on the page.
var scripts = document.getElementsByTagName('script');
var script = scripts[scripts.length - 1];
var scriptURL = script.src;
Please note that this code will only work if it executes directly within the JS file, i.e. not inside a document-ready callback or anything else that's called asynchronously. Then you can use any "get querystring parameter" JS (but make sure to replace any location.search references in there) to extract the argument.
I'd suggest you to put the value in a data-name argument though - that way you can simply use e.g. script.getAttribute('data-name') to get the value.
You can use the stack trace technique.
This technique will detect the source of the JS file the script is running from and it doesn't depend on the way you have injected the script. It can be dynamically injected (ajax) or in whatever method you can think of.
Just use the following code in your JS file:
const STACK_TRACE_SPLIT_PATTERN = /(?:Error)?\n(?:\s*at\s+)?/;
const STACK_TRACE_ROW_PATTERN1 = /^.+?\s\((.+?):\d+:\d+\)$/;
const STACK_TRACE_ROW_PATTERN2 = /^(?:.*?#)?(.*?):\d+(?::\d+)?$/;
const getFileParams = () => {
const stack = new Error().stack;
const row = stack.split(STACK_TRACE_SPLIT_PATTERN, 2)[1];
const [, url] = row.match(STACK_TRACE_ROW_PATTERN1) || row.match(STACK_TRACE_ROW_PATTERN2) || [];
if (!url) {
console.warn("Something went wrong. This probably means that the browser you are using is non-modern. You should debug it!");
return;
}
try {
const urlObj = new URL(url);
return urlObj.searchParams;
} catch (e) {
console.warn(`The URL '${url}' is not valid.`);
}
};
const params = getFileParams();
if ( params ) {
console.log(params.get('name'));
}
Note:
The params.searchParams will not work for IE browser, instead you can use params.search. But, for the sake of you nerves don't. Whoever is still using IE in 2020, just let him suffer.
I have this function:
function parseScript(_source) {
var source = _source;
var scripts = new Array();
while(source.indexOf("<script") > -1 || source.indexOf("</script") > -1) {
var s = source.indexOf("<script");
var s_e = source.indexOf(">", s);
var e = source.indexOf("</script", s);
var e_e = source.indexOf(">", e);
scripts.push(source.substring(s_e+1, e));
source = source.substring(0, s) + source.substring(e_e+1);
}
for(var i=0; i<scripts.length; i++) {
try {
eval(scripts[i]);
}
catch(ex) {
}
}
return source;
}
It parses and execute Javascript wonderfully except the when in <script type='text/javascript' src='scripts/gen_validatorv31.js'></script> the src file never gets executed.
The parser can only evaluate inline scripts in the file you have opened. To evaluate external scripts you would have to find their sources, probably using something like:
var scripts = source.match(/<script[^>]*src=[^>]*>/g);
if (scripts) {
for (var i = 0; i < scripts.length; i++) {
src = scripts[i].match(/src=("([^"]*)"|'([^']*)')/);
src = src[2] || src[3];
if (src) {
addScriptTag(src);
}
}
}
else console.log('no external scripts found');
where addScriptTag is described in this answer. addScriptTag adds the script to the head, if possible. It will need to be adapted if you need to add script to the body.
However... why do this? It is slow and messy to parse an entire HTML/Javascript page to get the scripts; for instance you might end up loading the same scripts twice or loading two scripts that don't work well together. Also the scripts may not work if inserted at a different point in the head or body. With AJAX you should only be loading the particular elements you need. Usually this means loading bits of data or HTML to be added to the page. If you have long scripts that are not needed at the beginning but might be needed later then it might be justified to dynamically add new scripts to the page. But in many cases probably better to load all needed scripts at the beginning. And if you really need to switch pages completely then isn't it better to use the old-fashioned method of linking to another page?
Is it possible from a Javascript code to find out "where" it came from?
I needed this to provide scripts that could run folder-agnostic, e.g.:
http://web1/service-a/script.js
http://web2/some-folder/service-b/script.js
And they're linked in:
http://web1/page1.html
http://web2/page2.html
The file script.js is identical in both locations but I would like them to be able to find out where it originates from so it can call the right web service methods (script.js from service-a should call service-a.method while script.js that is served from service-b should call service-b.method)
Is there a way to find out where script.js came from without using any server-side code?
Well, it's kind of a hack, you could grab all the <script> tags in the document, look at which one has the file name of the file, and do the logic from there.
document.getElementsByTagName('script'); is pretty much all you need. The rest is basic JS.
Even more interesting than looping through all of the returned elements (although that's probably safest), is that we can simply only look at the last element returned by the call above, as Javascript guarantees that must be the <script> tag we're in at the time of it being parsed (with the exception of deferred scripts). So this code:
var all_scripts = document.getElementsByTagName('script');
var current_script = scripts[all_scripts.length-1];
alert(current_script.src);
Will alert the source of the script tag used to include the current Javascript file.
You can analyze source of the html where script.js is included for tag and retrieve path of the script.js from there. Include next function in script.js and use it to retrieve the path.
function getPath() {
var path = null;
var scriptTags = document.getElementsByTagName("script");
for (var i = 0; i < scriptTags.length; i++) {
var scriptTagSrc = scriptTags.item(i).src;
if (scriptTagSrc && scriptTagSrc.indexOf("script.js") !== -1) {
path = scriptTagSrc;
break;
}
}
return path;
}