I'm trying to find one file which is of JSON type in my directory using JavaScript. However, when I look at google results, they claim that JavaScript cannot do such a thing because it is a client-side language. However, when I do the following code (which isn't what I want, but it works), which specifies the file I am looking for, it works. I was wondering why this is the case. Is it because I am using jQuery?
To clarify, I have a directory containing my html file and JSON file, and the Scene.js file is in a subdirectory. So, it looks like:
-labvtk
---ch4_CameraTypes.html (the html file)
---noise.json
---js
-----webgl
-------Scene.js
If this is the case, how would you suggest I find one file which is of JSON type( like *.json perhaps) instead of saying explicitly the file name (noise.json in this one case)?
Javascript code:
var Scene = {
objects : [],
getObject : function(alias){
for(var i=0; i<Scene.objects.length; i++){
if (alias == Scene.objects[i].alias) return Scene.objects[i];
}
return null;
},
loadObject : function(filename) {
var request = new XMLHttpRequest();
console.info('Requesting ' + filename);
request.open("GET",filename);
request.onreadystatechange = function() {
if (request.readyState == 4) {
if(request.status == 404) {
console.info(filename + ' does not exist');
}
else {
var o = JSON.parse(request.responseText);
o.remote = true;
Scene.addObject(o);
}
}
}
request.send();
},
addObject : function(object) {
...
and html file (which has some javascript in it)
...
<script type='text/javascript' src='js/gui/jquery-1.5.1.min.js'></script>
<script type='text/javascript' src='js/gui/jquery-ui-1.8.13.custom.min.js'></script>
<script type='text/javascript' src='js/webgl/Scene.js'></script>
...
function load(){
Scene.loadObject('noise.json');
}
...
This code was mostly taken from http://tinyurl.com/merdnch
The Google entries you have found are quite right: you can't search a server with Javascript. You can, as you have demonstrated, find a file if you already know the name.
The only way to search on the server is to implement a script on the server that does so. You might use PHP's scandir() or glob() functions, for example. There are many other ways.
This question might give you some pointers.
Related
A have a folder filled with files accessible to the end user, and am working on a javascript file to parse through them and deliver them as needed. However, rather than manually updating the list, I'd like the javascript to scan the folder and then list iterate through an array of the files in that folder. Is there a decent way in front-end JS to do this? All solutions I've looked into have turned out to be purely for Node.
For example, say I have a folder structure like so...
/ (Web Root)
|__ /Build_a_card
|__ /Cool pictures
|__ /Summer Pictures
summer_dog.gif
smiling_sun.svg
|__ /Winter Pictures
snowman.png
cat.jpg
And then in the javascript I'd run something like
var image_list = get_list("/Cool Pictures");
build_select_list(image_list);
function get_list(folder_to_look_in){
var the_list = ???
return the_list;
}
...
And then, for example, the JS is run, and after some parsing, the user would see...
<select>
<option value="summer_pictures/summer_dog.gif">summer_dog.gif</option>
<option value="summer_pictures/smiling_sun.svg">smiling_sun.svg</option>
<option value="winter_pictures/snowman.png">snowman.png</option>
<option value="cat.jpg">cat.jpg</option>
</select>
In an insane world, since the individual files in the folder are accessible to javascript, hypothetically I could brute-force every single possible file name in the folder and return success on each one:
function get_list(folder){
var list_of_files = {};
var starting_character = 0;
list_of_files = every_single_option({starting_character}, 0, 40, folder)
}
}
function every_single_option(existing_characters, current_depth, max_depth, folder){
this_string = String.fromCharCode(existing_characters);
if (request_url(this_string, folder)){
there_array[this_string] = this_string;
}
var there_array = {}
var i;
if (current_depth < max_depth){
while (i < 127){
let temp_array = there_array;
temp_array[i] = i;
mix_source(there_array, every_single_option(existing_characters, current_depth + 1, max_depth, folder))
}
}
return there_array;
}
function request_url(url, folder){
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "/" + folder + "/" + url);
oReq.send();
}
function mix(source, target) {
for(var key in source) {
if (source.hasOwnProperty(key)) {
target[key] = source[key];
}
}
}
but as mentioned, doing it that way would be insane (both ridiculously slow and very bad code design, resorting to brute-forcing your own website is just dumb.)
but it does hypothetically prove that there's no reason javascript shouldn't be able to just get a directory listing assuming public permissions. Alternatively, I could make some API with the backend that allows fetching a JSON that lists it, but that's requiring backend code for something that's a frontend process. I'm trying to pull this off with something sane and simple, but the question is... how?
(If you insist on posting a jquery way to do this, please also post a non-jquery way as well as there is no jquery available in my environment.)
So, refusing to admit it's impossible, I engineered a solution that works, and requires no API.
That said, the server has to not be actively blocking the javascript from viewing the directory. In other words, the server hasn't turned indexing off, and the directory doesn't have an index.html or equivalent to rewrite any attempt to index, and the server isn't doing some url-rewriting. In other words, this should work in any server environment that doesn't rewrite or block indexes.
Here's a rough draft (still buggy, needs finished):
var request = new XMLHttpRequest();
request.open('GET', '/my/directory/', true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var resp = request.responseText;
}
};
request.send();
var directory_listing = resp;
var regexp = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/i;
var match, files = [];
while ((match = regexp.exec(resp)) != null) {
files.push(match.index);
}
console.log(files);
Building off lilHar's answer, we can use DOMParser to create a shadow-DOM for the directory page we're accessing, and then use that to find any links we need:
// relative path to the desired directory
const directory = "/DIRECTORY-NAME/";
// selector for the relevant links in the directory's index page
const selector = "LINK SELECTOR";
const request = new XMLHttpRequest();
request.open("GET", directory, true);
request.onload = () => {
// succesful response
if(request.status >= 200 && request.status < 400)
{
// create DOM from response HTML
const doc = new DOMParser().parseFromString(request.responseText, "text/html");
// get all links
const links = doc.querySelectorAll(selector);
console.log("Links:", links);
links.forEach(link => {
// do stuff with the links
});
}
};
request.send();
Is there a decent way in front-end JS to do this?
No. Nor is that a way that isn't decent.
The front end can communicate with the server via HTTP or WebSockets.
Neither of those provides any built-in mechanism for exploring a filesystem.
You need the server to provide an API (e.g. a web service) which provides the information you want.
I think it might have asked before. But I couldn't find any results based on my search keywords.
In my use case I am configuring endpoints based on stage information [desktop, preprod, prod]. I am using golang for backend. In the backend I use the APP_STAGE environment variable to read the respective configs. For example,
fileName = APP_STAGE + "-endpoints.cfg"
And I export the variable before starting the server.
$export APP_STAGE="desktop"
And desktop-endpoints.cfg will look like this,
{
"featured" : {
"httpendpoint": {
"url": "http://localhost:8081/api/services/featured/"
}
},
"latest" : {
"httpendpoint": {
"url": "http://localhost:8081/api/services/latest/"
}
}
}
But how can I achieve this in client side [javascript]? I have files in the following structure,
app/
view.js
featured.js
home.js
Each of the file uses different endpoints to make ajax calls. How can read the stage config based on some variable [if not env variable] in javascript?
Could someone help me with this? I am fairly new to javascript.
Thanks.
JavaScript files are executed at client side, by the browser. The browser does not have access to the server config files, so it is the server's responsibility to read/get proper config values and make them available to the client.
There are multiple ways to deal with this. I will outline some possible solutions.
1. Include the correct endpoints in the HTML files
You may choose to include the correct endpoints in the HTML files that refer to the javascript files in which they would be used.
The HTML files would be templates and not static files, and you can use the html/template package to execute those templates to include the necessary URLs and everything else you need, and generate the final HTML that will be sent to the clients.
The HTML template may contain a <script> tag initializing certain JavaScript variables, which then can be used from the included JavaScript files.
Here's a simple example passing the featured httpendpoint.
HTML Template ("home.html"):
<html>
<head>
<script>
var featuredHttpEndpoint = "{{.FeaturedHttpEndpoint}}";
</script>
<script src="view.js"></script>
<script src="featured.js"></script>
<script src="home.js"></script>
</head>
<body>Your body</body>
</html>
And the handler that would serve this HTML template:
var homeTempl = template.Must(template.New("").ParseFiles("home.html"))
func homeHandler(w http.ResponseWriter, r *http.Request) {
m := map[string]interface{}{
// Insert the value of endpoint from your config
"FeaturedHttpEndpoint": "http://localhost:8081/api/services/featured/",
}
if err := homeTempl.Execute(w, m); err != nil {
// Handle error
}
}
Mapping the home handler e.g.:
http.HandleFunc("/index.html", homeHandler)
And make sure the home page is not cached, so the browser will always ask for a fresh copy in which your server can insert the actual config values.
2. Perform AJAX requests from the JavaScript files
You may choose to perform AJAX requests from the JavaScript files to query the necessary information. A simple example of this can be found in this question: Dynamically refresh a part of the template when a variable is updated golang
In a real-life example you would transmit all the config values that the client needs with one request (e.g. in JSON format), here I only transmit a single value.
Getting / sending only the featured httpendpoint:
In JavaScript:
var featuredHttpEndpoint = "";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var config = JSON.parse(xhr.responseText);
featuredHttpEndpoint = config.FeaturedHttpEndpoint;
}
}
xhr.open("GET", "/config.json", true);
try {
xhr.send();
} catch (err) {
// handle error
}
And the Go handler providing the config values:
func configHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
m := map[string]interface{}{
// Insert the value of endpoint from your config
"FeaturedHttpEndpoint": "http://localhost:8081/api/services/featured/",
}
if err := json.NewEncoder(w).Encode(m); err != nil {
// Handle error
}
}
Which must be mapped to the path the client calls, e.g.:
http.HandleFunc("/config.json", configHandler)
3. Use Javascript files as templates
You may also choose to make your Javascript files templates, and when serving them, you may use a template engine to include endpoints based on your environment / APP_STAGE. See point #1 as an example to serving templates.
If you're going down this path, you have to take care of properly configuring caching of the Javascript files, as the browser will not ask you again for the js files if their caching info says they are not expired.
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'].
I have a bunch of JavaScript files that I would like to include in the page, but I don't want to have to keep writing
<script type="text/javascript" src="js/file.js"></script>
So is there a way to include all files in a directory (unknown size)? Can I do something like...
$.getScript("js/*.js");
... to get all the JavaScript files in the "js" directory? How can I do this using jQuery?
In general, this is probably not a great idea, since your html file should only be loading JS files that they actually make use of. Regardless, this would be trivial to do with any server-side scripting language. Just insert the script tags before serving the pages to the client.
If you want to do it without using server-side scripting, you could drop your JS files into a directory that allows listing the directory contents, and then use XMLHttpRequest to read the contents of the directory, and parse out the file names and load them.
Option #3 is to have a "loader" JS file that uses getScript() to load all of the other files. Put that in a script tag in all of your html files, and then you just need to update the loader file whenever you upload a new script.
What about using a server-side script to generate the script tag lines? Crudely, something like this (PHP) -
$handle = opendir("scripts/");
while (($file = readdir($handle))!== false) {
echo '<script type="text/javascript" src="' . $file . '"></script>';
}
closedir($handle);
Given that you want a 100% client side solution, in theory you could probably do this:
Via XmlHttpRequest, get the directory listing page for that directory (most web servers return a listing of files if there is no index.html file in the directory).
Parse that file with javascript, pulling out all the .js files. This will of course be sensitive to the format of the directory listing on your web server / web host.
Add the script tags dynamically, with something like this:
function loadScript (dir, file) {
var scr = document.createElement("script");
scr.src = dir + file;
document.body.appendChild(scr);
}
It can be done fully client side, but all javascript file names must be specified.
For example, as array items:
function loadScripts(){
var directory = 'script/';
var extension = '.js';
var files = ['model', 'view', 'controller'];
for (var file of files){
var path = directory + file + extension;
var script = document.createElement("script");
script.src = path;
document.body.appendChild(script);
}
}
You can't do that in JavaScript, since JS is executed in the browser, not in the server, so it didn't know anything about directories or other server resources.
The best option is using a server side script like the one posted by jellyfishtree.
#jellyfishtree it would be a better if you create one php file which includes all your js files from the directory and then only include this php file via a script tag. This has a better performance because the browser has to do less requests to the server. See this:
javascripts.php:
<?php
//sets the content type to javascript
header('Content-type: text/javascript');
// includes all js files of the directory
foreach(glob("packages/*.js") as $file) {
readfile($file);
}
?>
index.php:
<script type="text/javascript" src="javascripts.php"></script>
That's it!
Have fun! :)
You could use something like Grunt Include Source. It gives you a nice syntax that preprocesses your HTML, and then includes whatever you want. This also means, if you set up your build tasks correctly, you can have all these includes in dev mode, but not in prod mode, which is pretty cool.
If you aren't using Grunt for your project, there's probably similar tools for Gulp, or other task runners.
You can't do that in Javascript from the browser... If I were you, I would use something like browserify. Write your code using commonjs modules and then compile the javascript file into one.
In your html load the javascript file that you compiled.
I was looking for an answer to this question and had my own problems. I found a couple solutions in various places and put them together into my own preferred answer.
function exploreFolder(folderURL,options){
/* options: type explaination
**REQUIRED** callback: FUNCTION function to be called on each file. passed the complete filepath
then: FUNCTION function to be called after loading all files in folder. passed the number of files loaded
recursive: BOOLEAN specifies wether or not to travel deep into folders
ignore: REGEX file names matching this regular expression will not be operated on
accept: REGEX if this is present it overrides the `ignore` and only accepts files matching the regex
*/
$.ajax({
url: folderURL,
success: function(data){
var filesLoaded = 0,
fileName = '';
$(data).find("td > a").each(function(){
fileName = $(this).attr("href");
if(fileName === '/')
return; //to account for the (go up a level) link
if(/\/\//.test(folderURL + fileName))
return; //if the url has two consecutive slashes '//'
if(options.accept){
if(!options.accept.test(fileName))
//if accept is present and the href fails, dont callback
return;
}else if(options.ignore)
if(options.ignore.test(fileName))
//if ignore is present and the href passes, dont callback
return;
if(fileName.length > 1 && fileName.substr(fileName.length-1) === "/")
if(options.recursive)
//only recurse if we are told to
exploreFolder(folderURL + fileName, options);
else
return;
filesLoaded++;
options.callback(folderURL + fileName);
//pass the full URL into the callback function
});
if(options.then && filesLoaded > 0) options.then(filesLoaded);
}
});
}
Then you can call it like this:
var loadingConfig = {
callback: function(file) { console.log("Loaded file: " + file); },
then: function(numFiles) { console.log("Finished loading " + numFiles + " files"); },
recursive: true,
ignore: /^NOLOAD/,
};
exploreFolder('/someFolderURL/', loadingConfig);
This example will call that callback on every file/folder in the specified folder except for ones that start with NOLOAD. If you want to actually load the file into the page then you can use this other helper function that I developed.
function getFileExtension(fname){
if(fname)
return fname.substr((~-fname.lastIndexOf(".") >>> 0) + 2);
console.warn("No file name provided");
}
var loadFile = (function(filename){
var img = new Image();
return function(){
var fileref,
filename = arguments[0],
filetype = getFileExtension(filename).toLowerCase();
switch (filetype) {
case '':
return;
case 'js':
fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src", filename);
break;
case "css":
fileref=document.createElement("link");
fileref.setAttribute("rel", "stylesheet");
fileref.setAttribute("type", "text/css");
fileref.setAttribute("href", filename);
break;
case "jpg":
case "jpeg":
case 'png':
case 'gif':
img.src = filename;
break;
default:
console.warn("This file type is not supported: "+filetype);
return;
}
if (typeof fileref !== undefined){
$("head").append(fileref);
console.log('Loaded file: ' + filename);
}
}
})();
This function accepts a JS | CSS | (common image) file and loads it. It will also execute the JS files.
The complete call that needs to be run in your script to load all images and* stylesheets and other scripts could look like this:
loadingConfig = {
callback: loadfile,
then: function(numFiles) { console.log("Finished loading " + numFiles + " files"); },
recursive: true,
ignore: /^NOLOAD/,
};
exploreFolder('/someFolderURL/', loadingConfig);
It works amazingly!
Another option that is pretty short:
<script type="text/javascript">
$.ajax({
url: "/js/partials",
success: function(data){
$(data).find('a:contains(.js)').each(function(){
// will loop through
var partial= $(this).attr("href");
$.getScript( "/js/partials/" + partial, function( data, textStatus, jqxhr ) {});
});
}
});
</script>
I'm writing a Chrome extension, and want to write one JS file, that provides several expected functions that aren't present in another, then load that other file. I'm after behavior similar to require in Perl, #include in C, or execfile in Python when passing the current modules locals and globals, as though the referenced file was inserted directly into the current script.
Most existing solutions I can find out there refer to embeddeding these "includes" inside script tags, but I'm not sure this applies (and if it does, an explanation of where exactly my extension is injecting all these script tags in the current page).
Update0
Note that I'm writing a content script. At least on the "user" side, I don't provide the original HTML document.
Well the best solution was Chrome-specific. The javascript files are listed in the order they are loaded in the extension's manifest.json, here's an extract of the relevant field:
{
"content_scripts": [
{
"js" : ["contentscript.js", "254195.user.js"]
}
]
}
The javascript files are effectively concatenated in the order given and then executed.
function load_script (url, cache)
{
var httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
httpRequest.open('GET', url, false);
if(!cache)
{
httpRequest.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
}
httpRequest.send(null);
eval(httpRequest.responseText);
var s = httpRequest.responseText.split(/\n/);
var r = /^function\s*([a-z_]+)/i;
for (var i = 0; i < s.length; i++)
{
var m = r.exec(s[i]);
if (m != null)
{
window[m[1]] = eval(m[1]);
}
}
}
load_script("/script.js",true);
We use this at our organization to do this. Seems to work well enough.
Did you try :
<script language="javascript" src="otherfile.js">
or (I'm not sure which... but I recall one of them working)
document.write('<script type="text/javascript" src="otherfile.js"></script>');