I am new to HTML/Javascript, as well as coding in general so bear with me :). I am trying to create a "Spot the Difference" game in html5 using javascript. Everything is local (on my machine). I have two pictures, of the same size, one with differences. To generate data about the clickable fields, I have a java program that reads both of the images and outputs all of the positions in which pixels are different into a XML file. My plan was to then use this XML file with my javascript to define where the user could click. However, it appears (correct me if I'm wrong) that javascript cannot read local XML files for security reasons. I do not want to use an ActiveXObject because I plan on putting this onto mobile devices via phone gap or a webkit object. Does anyone have a better approach to this problem, or perhaps a way to read local XML files via javascript? Any help would be greatly appreciated, thanks.
If you are planning to put this into a smart phones (iOS and Android) and read local files, I have done similar things with JSON (yes, please don't use XML).
Convert your output to JSON
Put this as part of your application package. For example, in Android, I put it as part of the .apk in /appFiles/json
Create a custom content provider that would read the local file. I create mine as content:// but you create whatever scheme you want. You could leverage android.content.ContentProvider in order to achieve custom URL Scheme. iOS has its own way to create custom scheme as well. The implementation simply read your local storage and give the content
To read it from Javascript, I simply call ajax with the custom scheme to get the json file. For example content://myfile/theFile.json simply redirect me to particular directory in local storage with /myfile/theFile.json appended to it
Below is the sample to override openFile() in the ContentProvider
public ParcelFileDescriptor openFile (Uri uri, String mode) {
try {
Context c = getContext();
File cacheDir = c.getCacheDir();
String uriString = uri.toString();
String htmlFile = uriString.replaceAll(CUSTOM_CONTENT_URI, "");
// Translate the uri into pointer in the cache
File htmlResource = new File(cacheDir.toString() + File.separator + htmlFile);
File parentDir = htmlResource.getParentFile();
if(!parentDir.exists()) {
parentDir.mkdirs();
}
// get the file from one of the resources within the local storage
InputStream in = WebViewContentProvider.class.getResourceAsStream(htmlFile);
// copy the local storage to a cache file
copy(in, new FileOutputStream(htmlResource));
return ParcelFileDescriptor.open(htmlResource, ParcelFileDescriptor.MODE_READ_WRITE);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
I hope it helps
I would suggest modifying your java program to output a JSON formatted file instead of XML. JSON is native to JavaScript and will be much simpler for you to load.
As for actually loading the data, i'm not sure what the best option is as you say you want to evenutally run this on a mobile device. If you were just making a normal website you could setup a web server using either Apache or IIS depending on your OS and put the files in the document root. Once you've done that you can load the JSON file via Ajax, which can easily be googled for.
Not sure if this helps any.
Since this is a local file, you can do this with jQuery
$.ajax({
type: "GET",
url: "your.xml",
dataType: "xml",
success: function(xml){
///do your thing
}
});
http://api.jquery.com/jQuery.ajax/
Related
I am fairly new to web development. I am using HTML and Javascript, specifically the Jexcel Javascript library, to create a spreadsheet webpage. The spread sheet is sourced from a CSV file stored in the working directory of my project. The problem is, when I make changes to that CSV file, they do not show up in my project until I rename the file (and change the filepath in my code respectively). I suspect this has to do with the webpage caching the source CSV file, but I am not sure. How would I go about disabling caching/making my table source from the CSV file everytime? I am using Tomcat Web Server as well. Thank you.
The code that is sourcing my spreadsheet is the following:
<script>
$('#spreadsheet').jexcel({
allowInsertRow: false,
allowInsertColumn: false,
allowDeleteRow: false,
allowDeleteColumn: false,
csv : 'data/test.csv',
csvHeaders : true,
defaultColWidth : '200px',
});
</script>
When changes are made to test.csv I want those changes to show the next time the page is refreshed, but this is not currently happening.
Update: Restarting the Web Server does make the changes show up, so I believe this is a caching issue. I am using Java Servelets on the Server Side of my code.
Browser side caching of resources is a common issue.
To prevent it, the easiest way is to append a version hash to resource url to force reload when modified, so you still benefit of cache feature when file hasn't changed.
Without information about the languages you use on server side, it's very difficult to help you more.
Here is the fonction I generally use to generate resources url :
function assetv($path) {
$hash = 'undefined';
if (file_exists($path)) {
$hash = filemtime($path);
if (!$hash) {
$hash = md5_file($path);
}
}
return urlFromPath($path) . "?v=" . $hash;
}
Of course, the "urlFromPath" depends on your app ;-)
[EDIT]
The browser loads your csv file using an url (data/test.csv) that is "used as cache key" (approximately).
So to force reload when file was modified, you need to change the url, for instance with a version number parameter (file name doesn't changes) :
data/test.csv?v=1
data/test.csv?v=2
As server side only is aware of file state, you need to generate the versionned url on server side when building your HTML.
Finally, instead of managing a version number manually, you can use a "natural" attribute of the file, as it's last modification time or a hash of it's content.
Thank you all for the suggestions. Ultimately I found out the problem was due to the fact that the csv file I was sourcing my data from was in the project folder and Tomcat does not update changes to that file immediately. I solved this by reading the data from a file stored outside the working directory on my machine.
I've built a simple html page with javascript in a separate file, called on a button press.
I've opened the html file in chrome, and the path resembles: file:///home/tom/projects/index.html
The javascript needs to read a JSON file (file:///home/tom/projects/mydata.json) which is in the same directory, using a hardcoded path.
I'm really struggling to do this. As I understand, this is because I'm using client side js (meaning I can't use the fs library for example), which is limiting my options.
According to the question here, I can't load the file if I use the URL in the format: file:///home/to.... as it gives me the error:
Cross origin requests are only supported for protocol schemes: HTTP, data, chrome, chrome-extension, https.
If I start an HTTP-server, as the answer suggests, I can use server-side modules, but if possible I would like to avoid this.
I've noticed many answers that suggest using a dialog box like this:
var selectedFile = document.getElementById('input').files[0];
function readFile (file_path) {
var reader = new FileReader();
reader.readAsText(file_path);
console.log(reader.substring(0, 100));
};
but I can't make this work with a path in the form: file:///home/tom/projects/mydata.json
Is there a way to load a .json file from a file:///home/to.... format URL using client-side javascript, with a hardcoded path (ie not asking the user to select the file from a selection box)?
This is a deliberate security restriction, to stop a user from being given, and then opening, a HTML page which then tries to read their disk.
Run your page in a webserver (as that question suggested) then you can either load the JSON from a URL (e.g. something like http://localhost/projects/mydata.json) using JavaScript, or use a server-side language to fetch it and display it inside the rendered HTML. Either way will work, the first way is probably simpler and closest to what you've got now.
It's always far better to serve HTML pages from a HTTP server, the way it's intended to be.
I want to create plugin mechanizm. It is, you can load js file on my website and run your js "plugin" (function) when this plugin is set to run (toggled as running).
All this I want to do without any server.
I mean, I want to keep in localstorage js files or path to this files.
It looks to be hard to do because js can't easy access files path.
I handle file by <input type="file"/>
And I react on onchange event. I get event where I can find selected file by event.srcElement.files[0]
With that I can create URL of that object by : URL.createObjectURL(event.srcElement.files[0])
And I tried to store that URL in localstorage but this URL is temporary.
Also I tried to store whole event or just file (event.srcElement.files[0]).
But I need to create string from that if I want to put it to the function .setItem :
localStorage.setItem("functionURL", JSON.stringify(this.functionURL));
.toString() creates [Object Event/File]
JSON.stringify() creates {} from [Object Event/File]
So, maybe is there a way to somehow remember file which we can use as a function without any server ?
So, maybe is there a way to somehow remember file which we can use as a function without any server ?
Basically, no. :-) Web storage only stores strings. You can't use a string to access a file on the user's local filesystem from your web page, for obvious security reasons.
You could, instead:
Make it possible for them to "upload" the file into your page (without a server) by having them identify the file in an input[type=file], reading its text (via the File API), and then storing that text in local storage
On page load, if local storage has code to run, run it
Offer the user a way to delete or update the code they've uploaded to the page
Since all of that happens in the browser, you don't need a server.
Web storage does have size limits, though they're pretty generous, (around 2.5-5MB) and per-origin, so you have that largely to yourself. But if you run into those limits, you could take it further by caching those files via a service worker, but the complexity goes up markedly. I'd start with web storage and only move on if you really need to support massive files.
#1 (reading the script file the user identifies via an input[type=file]) is really simple on modern browsers:
var file = input.files[0];
var fr = new FileReader();
fr.onload = function() {
// Use `fr.result` here, it's a string containing the text
};
fr.readAsText(file);
I could not find out why this part of my code doesn't work:
var loc = window.location.pathname;
var dir = loc.substring(0, loc.lastIndexOf('/'));
var FilePath = dir + "/" + FileName;
var file = new File("FilePath");
var reader = new FileReader();
reader.onload = function(e) {FileText = reader.result;}
reader.readAsText(file);
alert (FileText);
The intention is, I think, clear: FilePath contains the filename of a file (passed via parameter FileName) containing logging data (a plain ASCII text file, with one line per log entry), the file is located in the same directory as the web page is (loc), and I want to embed the text into my html document somewhere further down the code.
Since the logged lines are of different kinds (e.g. errors, warning, other blabla ...) each line needs to be parsed and processed.
I intended to split FileText into an array, and loop through it. I cannot, however, get readastext to work. Though, according to FireFox debugger, FilePath does contain the correct string, I get the NS_ERROR_FAILURE, which I, according to the sparse documentation I found about it, must consider to be the 'zillionst stupid way to say "File not found".
I found tons of other posts from people messing with the file API, and tons of snippets taken from the mozilla docs which don't help me out. I read that there are maybe other ways to read a file, e.g. through Ajax, JQuery ... but before I go that way ... is it really, really absolutely impossible to accomplish what I want using just plain JavaScript, and if it is possible, who can provide a code snippet?
Thanks very much,
Armin.
You have quotes around "FilePath":
var file = new File("FilePath");
This means it's going to try to load a file with the path "FilePath".
Pretty sure this is what you want:
var file = new File(FilePath);
On the other hand, Quentin is absolutely right. You're not going to be able to access local files if this code is running in a web page.
Since you are using window.location.pathname i assume that you are in a browser and want to use that code to "navigate" to files on the server based on the URL path.
I think your whole approach is wrong, and it would be a security issue to have something like that possible.
The File API can be used strictly on files selected by the user, and not on any file. The MDN description is self-explanatory:
Using the File API, which was added to the DOM in HTML5, it's now possible for web content to ask the user to select local files, then read the contents of those files. This selection can be done by either using an HTML element, or by drag and drop.
Yes, you can specify a path to any file in the File constructor method, but that doesn't mean you can access any file. Another excerpt from MDN:
This only works from privileged code, so web content can't do it. This protects users from the inherent security risks associated with allowing web content free access to the contents of their disks. If you pass a path to the File constructor from unprivileged code (such as web content), an exception will be thrown.
This code did the trick:
var objXMLhttp = new XMLHttpRequest()
objXMLhttp.open("GET",strFileName,true);
objXMLhttp.send();
and, in addition, an objXMLhttp.onreadystatechange=function() ... event handler must be implemented, which is the code acutally receiving the data, like so:
objXMLhttp.onreadystatechange=function()
{
if (objXMLhttp.readyState==4 && objXMLhttp.status==200)
{
var arrContents = objXMLhttp.responseText.split("\n"); // gotcha!
....
}
}
Easy win is to do an ajax request for the path...you should have your page that contains the js and files served by a web server. Any other way needs other priveleges and if you were to get files from a users computer without an uploader or anything like that would be a security breach
Currently I use this code to read a txt file with words and perform some operations. However, this particular code requires the html to be deployed on a server. Is there any workaround where I can replace this code with something else to read the file without the need of a server?
var xhr = new XMLHttpRequest();
xhr.open( "GET", "dictionary.txt", false );
xhr.send( null );
var words= xhr.responseText.split(",");
It is NOT possible to call Ajax outside your server domain (except you use scriptagproxy, that too requires you to have some server side configuration). So, in short, you CANNOT read files on your local computer using Ajax calls.
You might like this article.
The file selection can be made either by input or drag-and-drop (not otherwise). Please see: this
You cannot read files from the clients' computer, so the text file you are reading must be on the same server as your javascript.
However, if you are loading the HTML file from your computer (e.g. file://c:/../test.html), you might be able to read files located on ONLY your computer by using relative paths.
You can hide an iframe on the page, with its src='dictionary.txt',
and read or manipulate the iframe's local content when it's onload event fires.