Persistence storage JSON in a file using OS.File - javascript

How to do a Persistence storage in firefox addon sdk of JSON in a file using OS.File in OS independent way?
Like if I save the file in D:\file in windows, it wont work in linux or even on windows without drive :D.
How do I go about doing this?

To store realObject as JSON in the file MyFileName.json which is created/overwritten in the extension-data directory within the directory for the current profile, you could do something like:
Components.utils.import("resource://gre/modules/FileUtils.jsm");
Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
let asJSON = JSON.stringify(realObject,null);
let file2 = openFileInPrefsExtensionData("MyFileName.json");
overwriteTextFileFromString (file2, asJSON);
/**
* Open file in Extension's extension-data directory under the pref Directory.
* This is the correct place to store files for your extension under the profile's
* directory.
*/
function openFileInPrefsExtensionData(filename) {
let fileNameList = ["extension-data","MyExtensionID"];
fileNameList.push(filename);
//This does create all directories along the way to the file,
// but the file itself is not created.
return FileUtils.getFile("ProfD", fileNameList);
}
/**
* Overwrite a file from a string.
* Currently this just overwrites, without any callback function at the end
* of the write. If the write fails, then it is reported in the console,
* but not otherwise handled.
*/
function overwriteTextFileFromString(file,data) {
overwriteTextFile(file, data, function (status) {
});
}
/**
* Overwrite a file with a string.
*/
function overwriteTextFile(nsiFile, data, flags, callback) {
//data is data you want to write to file
//if file doesnt exist it is created
// You can also optionally pass a flags parameter here. It defaults to
// FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE;
//PR_RDONLY 0x01 Open for reading only.
//PR_WRONLY 0x02 Open for writing only.
//PR_RDWR 0x04 Open for reading and writing.
//PR_CREATE_FILE 0x08 If the file does not exist, the file is created. If the file exists, this flag has no effect.
//PR_APPEND 0x10 The file pointer is set to the end of the file prior to each write.
//PR_TRUNCATE 0x20 If the file exists, its length is truncated to 0.
//PR_SYNC 0x40 If set, each write will wait for both the file data and file status to be physically updated.
//PR_EXCL 0x80 With PR_CREATE_FILE, if the file does not exist, the file is created. If the file already exists, no action and NULL is returned.
let args = Array.prototype.slice.call(arguments,4);
if(typeof flags == "undefined") {
//These are already the defaults.
flags = FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE;
}
//XXX NOTE: Flags is currently not being used. I don't recall why I disabled its use.
var ostream = FileUtils.openSafeFileOutputStream(nsiFile);
var converter = Components.classes["#mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
var istream = converter.convertToInputStream(data);
// The last argument (the callback) is optional.
//asyncCopy automatically closes both the input and output streams upon completion.
NetUtil.asyncCopy(istream, ostream, function (status) {
if (!Components.isSuccessCode(status)) {
// Handle error!
Components.utils.reportError('error on write isSuccessCode = ' + status);
return;
}
// Data has been written to the file.
//send the status, and any other args to the callback function.
args.unshift(status);
if(typeof callback == "function" ) {
//there is a callback function..
callback.apply(callback, args);
}
});
}

Related

Can't display or read file object in Javascript

I have file object and I wish to grab the URL.
screenshot of file object on Chrome console
I tried to output the properties like below, but all are giving me "undefined" except type and date.
console.log("file: " + file.type);
console.dir(file.attachment.attributes);
console.dir(file.attachment.attributes.date);
console.dir(JSON.stringify(file.attachment.attributes.author));
console.dir(file.attachment.attributes.width);
Here's how the file type looks like as below.
screenshot of file type on Chrome console
Is there something wrong with how I try to read them?
My code is based on WordPress wp-plupload.js that comes with core WordPress. Yeah, I know I shouldn't edit the core codes but I was just experimenting.
UPDATE: Below is the code.
/**
* After a file is successfully uploaded, update its model.
*
* #param {plupload.Uploader} up Uploader instance.
* #param {plupload.File} file File that was uploaded.
* #param {Object} response Object with response properties.
*/
fileUploaded = function (up, file, response) {
var complete;
// Remove the "uploading" UI elements.
_.each(["file", "loaded", "size", "percent"], function (key) {
file.attachment.unset(key);
});
file.attachment.set(_.extend(response.data, { uploading: false }));
wp.media.model.Attachment.get(response.data.id, file.attachment);
complete = Uploader.queue.all(function (attachment) {
return !attachment.get("uploading");
});
if (complete) {
Uploader.queue.reset();
}
self.success(file.attachment);
};
UPDATE: I just realized the file is NOT a file object after all.
$isFile = file instanceof File;
console.log("File? " + $isFile);
I received a "File? false". It's not a blob too! But I still wonder why I can't read the object and get the URL.
Ok, I solved the problem this way. To get the file object, I need to call file.getNative() as stated here -> https://www.plupload.com/docs/v2/File
Thanks to all for your guidance, for without you I would be a lesser coder..

Google Apps Script Auto Duplicate Sheets between conversion of Excel to Google Sheets

I'm new to the coding game, learning how to code day by day.
Recently I'm hooked into Google App Script, learning to make a simple database.
I've tried to decode and re-code the script but I just can't get it working. It was supposed to convert and replace the existing google sheet instead the script just convert and duplicate the excel into many versions (1,2,3) of sheets from the original excel file.
// Convert the user's stored excel files to google spreadsheets based on the specified directories.
// There are quota limits on the maximum conversions per day: consumer #gmail = 250.
function convertCollection1()
{
var user = Session.getActiveUser(); // Used for ownership testing.
var origin = DriveApp.getFolderById("1dPsDfoqMQLCokZK4RN0C0VRzaRATr9AN");
var dest = DriveApp.getFolderById("1M6lDfc_xEkR4w61pUOG4P5AXmSGF1hGy");
// Index the filenames of owned Google Sheets files as object keys (which are hashed).
// This avoids needing to search and do multiple string comparisons.
// It takes around 100-200 ms per iteration to advance the iterator, check if the file
// should be cached, and insert the key-value pair. Depending on the magnitude of
// the task, this may need to be done separately, and loaded from a storage device instead.
// Note that there are quota limits on queries per second - 1000 per 100 sec:
// If the sequence is too large and the loop too fast, Utilities.sleep() usage will be needed.
var gsi = dest.getFilesByType(MimeType.GOOGLE_SHEETS), gsNames = {};
while (gsi.hasNext())
{
var file = gsi.next();
if(file.getOwner().getEmail() == user.getEmail())
gsNames[file.getName()] = true;
}
// Find and convert any unconverted .xls, .xlsx files in the given directories.
var exceltypes = [MimeType.MICROSOFT_EXCEL, MimeType.MICROSOFT_EXCEL_LEGACY];
for(var mt = 0; mt < exceltypes.length; ++mt)
{
var efi = origin.getFilesByType(exceltypes[mt]);
while (efi.hasNext())
{
var file = efi.next();
// Perform conversions only for owned files that don't have owned gs equivalents.
// If an excel file does not have gs file with the same name, gsNames[ ... ] will be undefined, and !undefined -> true
// If an excel file does have a gs file with the same name, gsNames[ ... ] will be true, and !true -> false
if(file.getOwner().getEmail() == user.getEmail() && !gsNames[file.getName()]
{
Drive.Files.insert (
{title: file.getName(), parents: [{"id": dest.getId()}]},
file.getBlob(),
{convert: true}
);
// Do not convert any more spreadsheets with this same name.
gsNames[file.getName()] = true;
}
}
}
}
The logic of the script is spot on. However, there are subtle nuisances in the function .getName() and Drive.Files.insertyou use that is causing the unintended behavior in the code.
folder.getName() gets the full name of the file, which includes the .xls/.xlsx extension. However, when you convert these files with Drive.Files.insert the extension is dropped. So your gsNames object has filenames without extension and but when the code tries to access the specific element using !gsNames[file.getName()] which has the file extension. It always returns undefined, which is evaluated as True.
Hence, you will need to remove the file extension before you try to check if the same file has already been converted. The regex to remove file extension was shamelessly copied from here. Your logic would be modified like so:
if(file.getOwner().getEmail() == user.getEmail() && !gsNames[file.getName().replace(/\.[^/.]+$/, "")])
Your file code will be:
function convertCollection1()
{
var user = Session.getActiveUser(); // Used for ownership testing.1aJcbdGhwliTs_CZ-3ZUvQmGRDzBM7fv9
var origin = DriveApp.getFolderById("1dPsDfoqMQLCokZK4RN0C0VRzaRATr9AN");
var dest = DriveApp.getFolderById("1M6lDfc_xEkR4w61pUOG4P5AXmSGF1hGy");
// Index the filenames of owned Google Sheets files as object keys (which are hashed).
// This avoids needing to search and do multiple string comparisons.
// It takes around 100-200 ms per iteration to advance the iterator, check if the file
// should be cached, and insert the key-value pair. Depending on the magnitude of
// the task, this may need to be done separately, and loaded from a storage device instead.
// Note that there are quota limits on queries per second - 1000 per 100 sec:
// If the sequence is too large and the loop too fast, Utilities.sleep() usage will be needed.
var gsi = dest.getFilesByType(MimeType.GOOGLE_SHEETS), gsNames = {};
while (gsi.hasNext())
{
var file = gsi.next();
if(file.getOwner().getEmail() == user.getEmail())
gsNames[file.getName()] = true;
Logger.log(JSON.stringify(gsNames))
}
// Find and convert any unconverted .xls, .xlsx files in the given directories.
var exceltypes = [MimeType.MICROSOFT_EXCEL, MimeType.MICROSOFT_EXCEL_LEGACY];
for(var mt = 0; mt < exceltypes.length; ++mt)
{
var efi = origin.getFilesByType(exceltypes[mt]);
while (efi.hasNext())
{
var file = efi.next();
// Perform conversions only for owned files that don't have owned gs equivalents.
// If an excel file does not have gs file with the same name, gsNames[ ... ] will be undefined, and !undefined -> true
// If an excel file does have a gs file with the same name, gsNames[ ... ] will be true, and !true -> false
if(file.getOwner().getEmail() == user.getEmail() && !gsNames[file.getName().replace(/\.[^/.]+$/, "")])
{
Drive.Files.insert (
{title: file.getName(), parents: [{"id": dest.getId()}]},
file.getBlob(),
{convert: true}
);
// Do not convert any more spreadsheets with this same name.
gsNames[file.getName()] = true;
}
}
}
Logger.log(JSON.stringify(gsNames))
}
Note the use of Logger.log(), use this in the future to determine what the program might be accessing vs what you think it is doing.
Cheers!

Electron will-download keeps getting interrupted

I am trying to download a file, but it keeps getting interrupted, and I have no idea why. I can not find any information on how to debug the reason it got interrupted either.
Here is where I am saving the file:
C:\Users\rnaddy\AppData\Roaming\Tachyon\games\murware\super-chain-reaction\web.zip
window.webContents.session.on('will-download', (event, item, webContents) => {
let path = url.parse(item.getURL()).pathname;
let dev = path.split('/')[3] || null;
let game = path.split('/')[4] || null;
if (!dev && !game) {
item.cancel();
} else {
item.setSavePath(Settings.fileDownloadLocation(dev, game, 'web'));
item.on('updated', (event, state) => {
let progress = 0;
if (state == 'interrupted') {
console.log('Download is interrupted but can be resumed');
} else if (state == 'progressing') {
progress = item.getReceivedBytes() / item.getTotalBytes();
if (item.isPaused()) {
console.log('Download is paused');
} else {
console.log(`Received bytes: ${item.getReceivedBytes()}; Progress: ${progress.toFixed(2)}%`);
}
}
});
}
});
Here is my listener that will trigger the above:
ipcMain.on(name, (evt) => {
window.webContents.downloadURL('http://api.gamesmart.com/v2/download/murware/super-chain-reaction');
});
Here is the output that I am getting in my console:
Received bytes: 0; Progress: 0.00%
Received bytes: 233183; Progress: 0.02%
Download is interrupted but can be resumed
I have a host file setup:
127.0.0.1 api.gamesmart.com
When I try to access the path http://api.gamesmart.com/v2/download/murware/super-chain-reaction in chrome, the file downloads just fine into my Downloads folder. So, what is causing this?
If you set the specific directory for downloading, you should use full file path with the file name in item.setSavePath() method. The best way to do it, fetching the file name from downloaditem object (item in your case) itself. You can use item.getFilename() to get the name of the current download item easily. here is the doc
And also there is a good way to get frequently used public system directory paths in electron. That is, using app.getPath(name) method. name would be the pre-defined String by electron for several directories. here is the doc
So, your complete setSavePath function would be,app.getPath("downloads") + "/" + item.getFilename()
In your case, if you are OK with your file path extraction method, only thing you are missing is filename at the end of the download path.
Of course you can use any other string as the file name if you wish. But remember to put correct extension though. :)
My solution was to use the correct Windows path separator (\), .e.g. 'directory\\file.zip'. Generally, Node.js uses / for any platform, but this seems to be sensitive about the path separator.

Exporting an array to excel file with cell formatting

I'm currently trying to export an array to an excel file with cell formatting.
I'm starting off with this code here:
https://github.com/SheetJS/js-xlsx/blob/master/tests/write.js
But the problem is that whenever I'm trying to export it (save the file as an xlsx file) this is the error that shows up in the console:
Uncaught TypeError: Cannot read property 'writeFileSync' of undefined xlsx.js:5182
writeSync xlsx.js:5182
writeFileSync xlsx.js:5173
process_xlsx Test.html:379
reader.onload Test.html:438
The last 2 lines are basically the part of the code which says
XLSX.writeFile(wb, 'sheetjs.xlsx');
I know wb is not undefined as if I try and do console.log of it, the excel spreadsheet shows up properly :|
Can someone help me with this? I'm also trying to have each cell have a different formatting (IE different color/bolded/filled/etc)
You base your code on a node.js test. The documentation states:
Writing Workbooks
For writing, the first step is to generate output data. The helper
functions write and writeFile will produce the data in various formats
suitable for dissemination. The second step is to actual share the
data with the end point. Assuming workbook is a workbook object:
nodejs write to file:
/* output format determined by filename */
XLSX.writeFile(workbook, 'out.xlsx');
/* at this point, out.xlsx is a file that you can distribute */
write to binary string (using FileSaver.js):
/* bookType can be 'xlsx' or 'xlsm' or 'xlsb' */
var wopts = { bookType:'xlsx', bookSST:false, type:'binary' };
var wbout = XLSX.write(workbook,wopts);
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
/* the saveAs call downloads a file on the local machine */
saveAs(new Blob([s2ab(wbout)],{type:""}), "test.xlsx")
So to sum up: You try to use node.js internal functions in the browser, which fails. If you try to follow the seconds approach ( XLSX.write() instead of XLSX.writeFile()), you should be fine.

Javascript and HTML5 File API - problems getting file correctly routed to function

I am wondering how to define a file reference for an HTML5 'file' object, to be used as input to a JavaScript function that will convert the file into Base64 encoding, WITHOUT using an interactive file input element. I have seen the HTML5Rocks examples, and numerous others, but they all use an <input type=file> element to read and gather inputs about the file to operate on. I am intending to take image files (i.e. binary) as input, and output Base64 strings. (Perhaps it is obvious, but I am new to the HTML5 and JavaScript worlds)
Some of my reading seems to indicate that this isn't possible for security reasons: JS would then be able to run arbitrary files. I wanted to double check.
What is the output of the 'file' input type? Can I manually mimic it in some way? (I found one reference here about just directly including the file itself inside the JS, but can you do that with a binary file? Frankly, not sure how I would do that on the FileMaker side, though, either. My plan, up to this point, was the export the file from FileMaker to a known location, then use that location as the input to the JavaScript)
The whole picture: I am trying to create a self contained web-viewer element in FileMaker 12. In FileMaker, I can dynamically define my HTML and JavaScript BEFORE running it. I want to dynamically hardcode the JavaScript to ALREADY contain the file reference based on the information from the database (i.e. path and filename). This is all running on a local machine, no server involved.
I am trying to minimize the interaction the end user has to make to get the file encoded: I don't want them to have to put the image into the database, and then also have to drop (or file-chooser) the image again in the web viewer. I want to keep all of this code inside the FileMaker database to make it much more portable and robust, i.e. not have to rely on an internet connection. So, the user puts their file into the database, which automatically detects that event, it calculates the JavaScript (including the path to the file), and the JavaScript runs the Base64 function on it, returning the encoded string to the database.
Perhaps I should do it the other way around: have the user drop the file into a JavaScript area that then copies it into the database. Not sure that the JavaScript would have any handles for interacting with the database, though.
------------------------ EDIT (in addition to some tagging and flagging of original question)
Let's ignore the whole FileMaker side of things for now. I decided to go the route of just using HTML5 and JavaScript as the file input portion (instead of trying to read it in FM and then output to JS). Just to see if I can get the JavaScript part to work.
Here is some code that I am playing with right now. It is mostly from the HTML5 Rocks demo, as well as the base64 encoding routine I found. However, I am running into problems with exactly how to define and call my reader, the onload event, and the encoding function. Any suggestions would be appreciated:
<script>
// From: http://www.html5rocks.com/en/tutorials/file/dndfiles/
// JC update: changing the handleFileSelect() function to do the base64 Processing
function base64Encode(aFile) {
/*
* base64.js - Base64 encoding and decoding functions
* See: http://developer.mozilla.org/en/docs/DOM:window.btoa
* http://developer.mozilla.org/en/docs/DOM:window.atob
* Copyright (c) 2007, David Lindquist <david.lindquist#gmail.com>
* Released under the MIT license
*
* JC, update: Removed the 'atob' section of code; only need ENcoding, not DEcoding.
*/
if (typeof btoa == 'undefined') {
function btoa(str) {
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var encoded = [];
var c = 0;
while (c < str.length) {
var b0 = str.charCodeAt(c++);
var b1 = str.charCodeAt(c++);
var b2 = str.charCodeAt(c++);
var buf = (b0 << 16) + ((b1 || 0) << 8) + (b2 || 0);
var i0 = (buf & (63 << 18)) >> 18;
var i1 = (buf & (63 << 12)) >> 12;
var i2 = isNaN(b1) ? 64 : (buf & (63 << 6)) >> 6;
var i3 = isNaN(b2) ? 64 : (buf & 63);
encoded[encoded.length] = chars.charAt(i0);
encoded[encoded.length] = chars.charAt(i1);
encoded[encoded.length] = chars.charAt(i2);
encoded[encoded.length] = chars.charAt(i3);
}
return encoded.join('');
}
}
}
function handleFileSelect(evt) {
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files; // FileList object - a FileList of File objects.
var fReader = new FileReader () ;
var output = [];
for (var i = 0, f; f = files[i]; i++) {
if ( !f.type.match('image.*')) { continue; } //To skip non-image files
fReader.onLoad = (function (aFile) { return base64Encode(aFile); } ) (f);
output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
f.size, ' bytes, last modified: ',
f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
'<br><br>' , fReader.readAsBinaryString(f) , '<br><br>', '</li>');
//This defines the 'onLoad' behavior/function...I think.
}
document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
}
function handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
}
// Setup the dnd listeners. [Slightly modified by JC]
var dropZone = document.getElementById('drop_zone');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', handleFileSelect, false);
</script>
No, in web browsers you can't access arbitrary files on user's computer. Never ever.
You can get files from the network (but read contents only if they are from the same origin or allowed via CORS, and file:// protocol doesn't allow it), IndexedDB database and Chrome's sandboxed filesystem (which is not user's filesystem — it only contains files you've put there yourself).
And you can create "files" yourself:
var file = new Blob(["file content"], {type:"text/plain"})
Blob is the base class of File and it's generally usable everywhere where input.files[] is.
You may have privileges to access local files from other JS-based environments like Widgets or browser extensions.

Categories

Resources