I want to check if a file exists locally, where the HTML file is located. It has to be JavaScript. JavaScript will never be disabled. jQuery is not good but can do.
By the way, I am making a titanium app for Mac so I am looking for a way of protecting my files from people who click "show package contents".
Your question is ambiguous, so there are multiple possible answers depending on what you're really trying to achieve.
If you're developping as I'm guessing a desktop application using Titanium, then you can use the FileSystem module's getFile to get the file object, then check if it exists using the exists method.
Here's an example taken from the Appcelerator website:
var homeDir = Titanium.Filesystem.getUserDirectory();
var mySampleFile = Titanium.Filesystem.getFile(homeDir, 'sample.txt');
if (mySampleFile.exists()) {
alert('A file called sample.txt already exists in your home directory.');
...
}
Check the getFile method reference documentation
And the exists method reference documentation
For those who thought that he was asking about an usual Web development situation, then thse are the two answers I'd have given:
1) you want to check if a server-side file exists.
In this case you can use an ajax request try and get the file and react upon the received answer. Although, be aware that you can only check for files that are exposed by your web server. A better approach would be to write a server-side script (e.g., php) that would do the check for you, given a filename and call that script via ajax. Also, be aware that you could very easily create a security hole in your application/server if you're not careful enough.
2) you want to check if a client-side file exists.
In this case, as pointed you by others, it is not allowed for security reasons (although IE allowed this in the past via ActiveX and the Scripting.FileSystemObject class) and it's fine like that (nobody wants you to be able to go through their files), so forget about this.
Since 'Kranu' helpfully advises 'The only interaction with the filesystem is with loading js files . . .', that suggests doing so with error checking would at least tell you if the file does not exist - which may be sufficient for your purposes?
From a local machine, you can check whether a file does not exist by attempting to load it as an external script then checking for an error. For example:
<span>File exists? </span>
<SCRIPT>
function get_error(x){
document.getElementsByTagName('span')[0].innerHTML+=x+" does not exist.";
}
url=" (put your path/file name in here) ";
url+="?"+new Date().getTime()+Math.floor(Math.random()*1000000);
var el=document.createElement('script');
el.id="123";
el.onerror=function(){if(el.onerror)get_error(this.id)}
el.src=url;
document.body.appendChild(el);
</SCRIPT>
Some notes...
append some random data to the file name (url+="?"+new Date etc) so that the browser cache doesn't serve an old result.
set a unique element id (el.id=) if you're using this in a loop, so that the get_error function can reference the correct item.
setting the onerror (el.onerror=function) line is a tad complex because one needs it to call the get_error function AND pass el.id - if just a normal reference to the function (eg: el.onerror=get_error) were set, then no el.id parameter could be passed.
remember that this only checks if a file does not exist.
You can use this
function LinkCheck(url)
{
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
return http.status!=404;
}
Javascript cannot access the filesystem and check for existence. The only interaction with the filesystem is with loading js files and images (png/gif/etc).
Javascript is not the task for this
Fortunately, it's not possible (for security reasons) to access client-side filesystem with standard JS. Some proprietary solutions exist though (like Microsoft's IE-only ActiveX component).
If you want to check if file exists using javascript then no, as far as I know, javascript has no access to file system due to security reasons..
But as for me it is not clear enough what are you trying to do..
An alternative:
you can use a "hidden" applet element which implements this exist-check using a privileged action object and override your run method by:
File file = new File(yourPath);
return file.exists();
One way I've found to do this is to create an img tag and set the src attribute to the file you are looking for. The onload or onerror of the img element will fire based on whether the file exists. You can't load any data using this method, but you can determine if a particular file exists or not.
No need for an external library if you use Nodejs all you need to do is import the file system module. feel free to edit the code below:
const fs = require('fs')
const path = './file.txt'
fs.access(path, fs.F_OK, (err) => {
if (err) {
console.error(err)
return
}
//file exists
})
Related
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 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
I am creating a firefox extension that lets the operator perform various actions that modify the content of the HTML document. The operator does not edit HTML, they take other actions and my extension modifies the document by inserting elements, adding attributes, and so forth.
When the operator is finished, they need to be able to save the HTML document as a file (or have my extension send it to an internet destination, but this is not required since they can email the saved file).
I thought maybe the changes made by the javascript code in my extension would be reflected in the HTML document, but when I ask the firefox browser to "view source" after making modifications, it displays the original HTML text.
My questions are:
#1: What is the easiest way for the operator to save the HTML document with all the changes my extension has made?
#2: What is the easiest way for the javascript code in my extension to process the HTML document contents and write to an HTML file on the local disk?
#3: Is any valid HTML content incapable of accurate representation in the saved file?
#4: Is the TreeWalker part of the solution (see below)?
A couple observations from my research so far:
I've read about the TreeWalker object, which seems to provide a fairly painless way for an extension to walk through everything (?or almost everything?) in the HTML document. But does it expose everything so everything in the original (and my modifications) can be saved without losing anything of importance?
Does the TreeWalker walk through the HTML document in the "correct order" --- the order necessary for my extension to generate the original and/or modified HTML document?
Anything obscure or tricky about these problems?
Ok so I am assuming here you have access to page DOM. What you need to do it basically make changes to the dom and then get all the dom code and save it as a file. Here is how you can download the page's html code. This will create an a tag which the user needs to click for the file to download.
var a = document.createElement('a'), code = document.querySelectorAll('html')[0].innerHTML;
a.setAttribute('download', 'filename.html');
a.setAttribute('href', 'data:text/html,' + code);
Now you can insert this a tag anywhere in the DOM and the file will download when the user clicks it.
Note: This is sort of a hack, this injects entire html of the file in the a tag, it should in theory work in any up to date browser (except, surprise, IE). There are more stable and less hacky ways of doing it like storing it in a file system API file and then downloading that file instead.
Edit: The document.querySelectorAll line accesses the page DOM. For it to work the document must be accessible. You say you are modifying DOM so that should already be there. Make sure you are adding the code on the page and not your extension code. This code will be at the same place as your DOM modification code, not your extension pages that can't access the DOM.
And as for the a tag, it will be inserted in the page. I skipped the steps since I assumed you already know how to manipulate DOM and also because I don't know where you would like to add the link. And you can skip the user action of clicking the link too, but it's a hack and only works in modern browsers. You can insert the a tag somewhere in the original page where user won't see it and then call the a.click() function to simulate a click event on the link. But this is not a legit way and I personally only use it on my practice projects to call click event listeners.
I can only test this on chrome not on FF but try this code, this will not require you to even add the a link to DOM. You need to add this next to the DOM manipulation code. This will work if luck is on your side :)
var a = document.createElement('a'), code = document.querySelectorAll('html')[0].innerHTML;
a.setAttribute('download', 'filename.html');
a.setAttribute('href', 'data:text/html,' + code);
a.click();
There is no easy way to do this with the web API only, at least when you want a result that does not omit stuff like the doctype or comments. You could still write a serializer yourself that goes through document.childNodes and serialized according to the node type (Element.outerHTML, Comment.data and so on).
Luckily, you're writing a Firefox add-on, so you have access to a lot more (powerful) stuff.
While still not 100% perfect, the nsIDocumentEncoder implementations will produce pretty decent results, that should only differ in some whitespace and explicit charset declaration at most (everything else is a bug).
Here is an example on how one might use this component:
function serializeDocument(document) {
const {
classes: Cc,
interfaces: Ci,
utils: Cu
} = Components;
let encoder = Cc['#mozilla.org/layout/documentEncoder;1?type=text/html'].createInstance(Ci.nsIDocumentEncoder);
encoder.init(document, 'text/html', Ci.nsIDocumentEncoder.OutputLFLineBreak | Ci.nsIDocumentEncoder.OutputRaw);
encoder.setCharset("utf-8");
return encoder.encodeToString();
}
If you're writing an SDK add-on, stuff gets more complicated as the SDK abstracts some important stuff away. You'll need to go through the chrome module, and also figure out the active window and tab yourself. Something like Services.wm.getMostRecentWindow("navigator:browser").content.document (Services.jsm) should do the trick.
In XUL overlay add-ons, content.document should suffice to get the document of the currently active tab, and you have Components access already.
Still, you need to let the user choose a file destination, usually through nsIFilePicker and then actually write the file, by using something like a file stream or the fully async OS.File API.
Looks like I get to answer my own question, thanks to someone in mozilla #extdev IRC.
I got totally faked out by "view source". When I didn't see my modifications in the window displayed by "view source", I assumed the browser would not provide the information.
However, guess what? When I "file" ===>> "save page as...", then examine the page contents with a plain text editor... sure enough, that contained the modifications made by my firefox extension! Surprise!
A browser has no direct write access to the local filesystem. The only read access it has is when explicitly provide a file:// URL (see note 1 below)
In your case, we are explicitly talking about javascript - which can read and write cookies and local storage. It can also send stuff back to the server and retrieve it, e.g. using AJAX.
Stuff you put in local storage/cookies is effectively not accessible to other programs (such as email clients).
It is possible to create very long mailto: URLs (see note 2) but only handles inline content in the email and you're going to run into all sorts of encoding issues that you're not ready to deal with.
Hence I'd recommend pursuing storage serverside via AJAX - and look at local storage once you've got this sorted/working.
Note 1: this is not strictly true. a trusted, signed javascript has access to additional functions which may include direct file access.
Note 2: (the limit depends on the browser and the email client - Lotus Notes truncaets the content rather a lot)
Trying to write to a text file w/ Adobe Acrobat Reader utilizing AcroJS.
As a concept I got how to use trusted functions in Acrobat but when I tried to run following example to save (different problem then the original) the pdf form under a different name using this.saveAs(..) received an error.
My question is two fold;
1- Why do I get "Security settings prevent access to this property or method" error and how do I get rid of it?
trusted function in javascript folder is as follwos (copeid off the web)
var mySaveAs = app.trustedFunction( function(cFlName)
{
app.beginPriv();
try{
this.saveAs(cFlName);
}
catch(e){
app.alert("Error During Save " + e.message );
}
app.endPriv();
});
I am calling the trusted function from the doucment as follwos and expecting a file with the name sample.pdf will be generated inside "C:/test"
if(typeof(mySaveAs) == "function")
{
mySaveAs("/C/test/sample.pdf");
}
else
{
app.alert("Missing Save Function");
}
2- How do I write to a text file? Here I want to extract some field values from the PDF form and write those into a text file (or XML)!
As you might have guessed, it's a security measure to prevent malicious scripts from causing havoc. You'll need to turn down the security settings. To do this, Ctrl+K into Preferences, go to the Enhanced Security tab and disable it.
For addition information on Enhanced Security, refer to: http://www.adobe.com/devnet-docs/acrobatetk/tools/AppSec/enhanced.html
As far as I know, there aren't any functions that will allow you to write arbitrary data to a text file or XML file. However, you have a couple of options:
Use Doc.exportAsText (text) and Doc.exportAsFDF (XML) to export data from carefully crafted fields. This isn't very straightforward and a little awkward, but it works.
Use Net.HTTP.request or Net.SOAP to send data to an ad-hoc local web server (eg: something simple, running Python or PHP) and let them handle the request. This allows you to do pretty much anything you want, but requires more work to setup the server.
See: Acrobat JS API Reference
When I saw many sites' source code, parameters were passed to the linking file (CSS/JavaScript).
In the Stack Overflow source, I got
<script type="text/javascript" src="http://sstatic.net/js/master.js?v=55c7eccb8e19"></script>
Why is master.js?v=55c7eccb8e19 used?
I am sure that JavaScript/CSS files can't get the parameters.
What is the reason?
It is usually done to prevent caching.
Let's say you deploy version 2 of your new application and you want to cause the clients to refresh their CSS, you could add this extra parameter to indicate that it should re-request it from the server. Of course there are other approaches as well, but this is pretty simple.
As the others have said, it's probably an attempt to control caching, although I think it's best to do so by changing the actual resource name (foo.v2.js, not foo.js?v=2) rather than a version in the query string. (That doesn't mean you have to rename files, there are better ways of mapping that URL to the underlying file.) This article, though four years old and therefore ancient in the web world, is still a quite useful discussion. In it, the author claims that you don't want to use query strings for versions because:
...According the letter of the HTTP caching specification, user agents should never cache URLs with query strings. While Internet Explorer and Firefox ignore this, Opera and Safari don’t...
That statement may not be quite correct, because what the spec actually says is
...since some applications have traditionally used GETs and HEADs with query URLs (those containing a "?" in the rel_path part) to perform operations with significant side effects, caches MUST NOT treat responses to such URIs as fresh unless the server provides an explicit expiration time...
(That emphasis at the end is mine.) So using a version in the query string may be fine as long as you're also including explicit caching headers. Provided browsers implement the above correctly. And proxies do. You see why I think you're better off with versions in the actual resource locator, rather than query parameters (which [again] doesn't mean you have to constantly rename files; see the article linked above for more). You know browsers, proxies, etc. along the way are going to fetch the updated resource if you change its name, which means you can give the previous "name" a never-ending cache time to maximize the benefit of intermediate caches.
Regarding:
I am sure that Js/CSS files can't get the parameters.
Just because the result coming back is a JavaScript or CSS resource, it doesn't mean that it's a literal file on the server's file system. The server could well be doing processing based on the query string parameters and generating a customized JavaScript or CSS response. There's no reason I can't configure my server to route all .js files to (say) a PHP handler that looks at the query string and returns something customized to match the fields given. Thus, foo.js?v=2 may well be different from foo.js?v=1 if I've set up my server to do so.
That's to avoid the browser from caching the file. The appending version name has no effect on the JavaScript file, but to the browser's caching engine it looks like a unique file now.
For example, if you had scripts.js and the browser visits the page, they download and cache (store) that file to make the next page visit faster. However, if you make a change the browser may not recognize it until the cache has expired. However, scripts.js?v2 now makes the browser force a re-fetch because the "name's changed" (even though it hasn't, just the contents have).
A server-side script generating the CSS or JavaScript code could make use of them, but it is probably just being used to change the URI when the the content of the file changes so that old, cached versions won't cause problems.
<script type="text/javascript">
// front end cache bust
var cacheBust = ['js/StrUtil.js', 'js/protos.common.js', 'js/conf.js', 'bootstrap_ECP/js/init.js'];
for (i=0;i<cacheBust.length;i++){
var el = document.createElement('script');
el.src = cacheBust[i]+"?v=" + Math.random();
document.getElementsByTagName('head')[0].appendChild(el);
}
</script>
This is to force the browser to re-cache the .js file if there has been any update.
You see, when you update your JS on a site, some browsers may have cached the old version (to improve performace). Sicne you want them to use your new one, you can append something in the query-field of the name, and voíla! The browser re-fetches the file!
This applies to all files sent from the server btw.
Since javascript and css files are cached by the client browser, so we append some numeric values against their names in order to provide the non-cached version of the file
"I am sure that JavaScript /CSS files can't get the parameters"
function getQueryParams(qs) {
qs = qs.split("+").join(" ");
var params = {},
tokens, re = /[?&]?([^=]+)=([^&]*)/g;
while (tokens = re.exec(qs)) {
params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
}
return params;
}
This is referred to as Cache Busting.
The browser will cache the file, including the querystring. Next time the querystring is updated the browser will be forced to download the new version of the file.
There are various types of cache-busting, for example:
Static
Date/Time
Software Version
Hashed-Content
I've wrote an article on cache busting previously which you may find useful:
http://curtistimson.co.uk/front-end-dev/what-is-cache-busting/