Write to a file identified by its Url in pure javascript - javascript

I would need to add data to a text file from javascript.
I've found the following code :
var file = showFilePicker(window, "", Components.interfaces.nsIFilePicker.modeSave, "", function(fp) {return fp.file;});
var outputStream = Components.classes["#mozilla.org/network/file-output-stream;1"].createInstance( Components.interfaces.nsIFileOutputStream);
outputStream.init(file, 0x02 | 0x08 | 0x20, 0644, 0);
outputStream.write(someText, someText.length);
outputStream.close();
However it takes a file chosen by the user thanks to a file picker.
In my case, I'd like to write to a text file identified by its URL (for example : C://.../text.js)

This probably isn't possible in a browser because of security restrictions. You can do it with NodeJS, though.

Related

Get the entire HTML + CSS + JS of the page, and send it to a web service

I am writing a web service in C# using NReco.PdfConverter and wkhtml that would convert web pages into PDF files.
The web pages (on SharePoint) require authorization and also contain a form that the user needs to fill in, therefore the web service cannot simply access the URL of that page and download it.
The JavaScript and CSS files are also important for the correct rendering of the form, including dozens of JS files and stylesheets from SharePoint.
So far my best idea is this:
When user clicks "Generate PDF", JavaScript will convert the entire current page into a single string (appending the CSS files and JS files inline);
POST that string to the webservice using $.ajax().
Using NReco.PdfConverter, it is trivial to convert that string to PDF and save it into the file:
var converter = new HtmlToPdfConverter
{
Margins = new PageMargins
{
Top = 0,
Bottom = 0,
Left = 0,
Right = 0
},
CustomWkHtmlArgs = "--print-media-type"
};
converter.GeneratePdf(htmlContent);
How would one even approach the idea of generating a single-page HTML (including the state of the checkboxes, text inside the forms etc.) in the browser?
Is it something tremendously complicated? Is anyone aware of another solution?
You can pass authorization cookie (or header) using appropriate wkhtmltopdf option, for example (if WebForms authentication is used):
var pdfGen = new HtmlToPdfConverter();
pdfGen.CustomWkHtmlArgs = String.Format(" --cookie {0} {1} ",
FormsAuthentication.FormsCookieName,
Request.Cookies[FormsAuthentication.FormsCookieName] );
pdfGen.GeneratePdfFromFile("your_sharepoint_web_page_url", null, "output.pdf");
--- UPDATE ---
for HTTP Basic auth:
pdfGen.CustomWkHtmlArgs = String.Format(" --username {0} --password {1}", username, pwd );

Saving text from website using Firefox extension, wrong characters saved

Sorry about the vague title but I'm a bit lost so it's hard to be specific. I've started playing around with Firefox extensions using the add-on SDK. What I'm trying to to is to watch a page for changes, a Twitch.tv chat window in this case, and save those changes to a file.
I've gotten this to work, every time something changes on the page it gets saved. But, "unusual" characters like for example something in Korean doesn't get saved properly. I think this has to do with encoding of the file/string? I tried saving the same characters by copy-pasting them into notepad, it asked me to save in Unicode and when I did everything worked fine. So I figured, ok, I'll change the encoding of the log file to unicode as well before writing to it. Didn't exactly work... Now all the characters were in some kind of foreign language.
The code I'm using to write to the file is this:
var {Cc, Ci, Cu} = require("chrome");
var {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm");
var file = FileUtils.getFile("Desk", ["mylogfile.txt"]);
var stream = FileUtils.openFileOutputStream(file, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_APPEND);
stream.write(data, data.length);
stream.close();
I looked at the description of FileUtils.jsm over at MDN and as far as I can tell there's no way to tell it which encoding I want to use?
If you don't know a fix could you give me some good search terms because I seem to be coming up short on that front. Since I know basically nothing on the subject I'm flailing around in the dark a bit at the moment.
edit:
This is what I ended up with (for now) to get this thing working:
var {Cc, Ci, Cu} = require("chrome");
var {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm");
var file = Cc['#mozilla.org/file/local;1']
.createInstance(Ci.nsILocalFile);
file.initWithPath('C:\\temp\\temp.txt');
if(!file.exists()){
file.create(file.NORMAL_FILE_TYPE, 0666);
}
var charset = 'UTF-8';
var fileStream = Cc['#mozilla.org/network/file-output-stream;1']
.createInstance(Ci.nsIFileOutputStream);
fileStream.init(file, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_APPEND, 0x200, false);
var converterStream = Cc['#mozilla.org/intl/converter-output-stream;1']
.createInstance(Ci.nsIConverterOutputStream);
converterStream.init(fileStream, charset, data.length,
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
converterStream.writeString(data);
converterStream.close();
fileStream.close();
Dumping just the raw bytes (well, raw jschars actually) won't work. You need to first convert the data into some sensible encoding.
See e.g. the File I/O Snippets. Here are the crucial bits of creating a converter output stream wrapper:
var converter = Components.classes["#mozilla.org/intl/converter-output-stream;1"].
createInstance(Components.interfaces.nsIConverterOutputStream);
converter.init(foStream, "UTF-8", 0, 0);
converter.writeString(data);
converter.close(); // this closes foStream
Another way is to use OS.File + TextConverter:
let encoder = new TextEncoder(); // This encoder can be reused for several writes
let array = encoder.encode("This is some text"); // Convert the text to an array
let promise = OS.File.writeAtomic("file.txt", array, // Write the array atomically to "file.txt", using as temporary
{tmpPath: "file.txt.tmp"}); // buffer "file.txt.tmp".
It might be even possible to mix both. OS.File has the benefit that it will write data and access files off the main thread (so it won't block the UI while the file is being written).

download string object content as plain text file with Mozilla Firefox extension

In my FF extension I create an object (a string) retrieving data from the DOM.
Now I need to download a plain text file with the string content. The result should be a CSV file.
I read about addDownload method but I miss a lot of pieces... any hint?
Mainly I don't know how to:
"transform" my string in a downloadable object (a file?)
correctly call the addDownload method (nsIURI, etc)
Thank you very much for the help.
You have a number of approaches. The old-school way is to manipulate nsIFile and nsIFileOutputStream directly, although you can't write null bytes this way. You can also create an nsIStringInputStream from your string and write that to your output stream, or you can use nsIAsyncStreamCopier to copy it asynchronously. FileUtils.jsm and NetUtil.jsm exist to try to make this easier for you.
However, if you are targetting new enough versions of Firefox, you can ignore all that and use the OS.File API instead.
This is part of my extension, it shows the save as dialog so the user can pick the correct location (you can skip that part or try to find out where the downloads should be placed automatically)
const nsIFilePicker = Components.interfaces.nsIFilePicker;
var fp = Components.classes["#mozilla.org/filepicker;1"]
.createInstance(nsIFilePicker);
fp.init(window, "Save as", nsIFilePicker.modeSave);
fp.appendFilters(nsIFilePicker.filterHTML);
fp.appendFilters(nsIFilePicker.filterAll);
var rv = fp.show();
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
var file = fp.file;
// work with returned nsILocalFile...
// Check that it has some extension
var name = file.leafName;
if (-1==name.indexOf('.'))
file.leafName = name + '.html' ;
// file is nsIFile, data is a string
var foStream = Components.classes["#mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
// use 0x02 | 0x10 to open file for appending.
foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0);
// write, create, truncate
foStream.write(data, data.length);
foStream.close();

Selenium: enable XPCOM access and write to a file from Javascript in Firefox

In this question there is an example how to request XPCOM access from Javascript:
How to create a file using javascript in Mozilla Firefox
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
I was hoping to find a way to enable XPCOM access in similar manner for my Selenium test scripts, so that Javascript could directly write RAW image data to a file. This actually continues my previous questions how to extract pixel data from in optimized manner:
Firefox, Selenium, toDataURL, Uint8ClampedArray and Python
What I am hoping to achieve
Enable XPCOM access for Javascripts run through Selenium
Render image on Canvas
Read canvas pixels as raw image data (public API should be available on the canvas itself)
Write RAW image data to a file using XPCOM interfaces in a known path location
Note: PNG etc. encoding is unaccetable. This must be raw data for the speed, as it will be directly feed to a video encoding,
It seems to me that this blog post is what you are looking for:
Save to local files with XPCOM for Selenium Firefox Chrome
function saveFile(fileName, val){
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
} catch (e) {
//alert("Permission to save file was denied.");
}
var file = Components.classes["#mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(fileName);
if (file.exists() == false) {
//alert("Creating file... " );
file.create( Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 420 );
}
var outputStream = Components.classes["#mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
outputStream.init( file, 0x04 | 0x08 | 0x20, 420, 0 );
//UTF-8 convert
var uc = Components.classes["#mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
uc.charset = "UTF-8";
var data_stream = uc.ConvertFromUnicode(val);
var result = outputStream.write(data_stream, data_stream.length );
outputStream.close();
}
You'll have to adapt it for your situation (RAW datatype) but that's basically it!
I don't know much about Selenium, but IF you can install an extension on the version of Firefox that will be running the page, you can inject your own script into the page when it loads. See this SO answer

Browser - file writer extension?

Is there any chrome or firefox extension that allows javascript to create write files in client's PC?
What do you want to do?
HTML5 has a File API. This is the best solution because it allows selection of the file to be wholly under user control.
If you must, you can make your own NPAPI plugin which exposes itself to scripting (aka NPRuntime) and performs native local file operations on behalf of Javascript in the page. Or, in IE, new ActiveXObject("Scripting.FileSystemObject") may yield a FileSystemObject (depending on ActiveX settings). But please don't.
var file = Components.classes["#mozilla.org/filelocal;1"].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath("Pathforfile");
file.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 420 );
var outputStream = Components.classes["#mozilla.org/network/file-output-stream;1"].createInstance( Components.interfaces.nsIFileOutputStream );
outputStream.init( file, 0x04 | 0x08 | 0x20, 420, 0 );
var output="Texttowriteinfile";
var result = outputStream.write( output, output.length );
outputStream.close();

Categories