Creating File using extension firefox - javascript

I am trying to create a file in my extension directory and I have this code:
AddonManager.getAddonByID(" extension id here ", function(addon)
{
var uri = addon.getResourceURI("hello.txt");
var file = Components.classes["#mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
var stringUri = uri.asciiSpec;
stringUri = stringUri.replace(new RegExp(/\//g), '\\');
stringUri = stringUri.slice(8);
alert(stringUri);
try{
file.initWithPath(stringUri);
} catch(e) {
alert(e);
}
alert(addon.hasResource("hello.txt"));
});
For some reason, the last alert shows always false and file doesn't exist. What am I doing wrong?
I also put unpack true unpack tags in the install.rdf to see my extension directory.

initWithPath accepts only local filesystem paths. Assuming uri is a file url, you can do the conversion like this
var path = uri.QueryInterface(Components.interfaces.nsIFileURL).file.path

Related

How to download multiple files from Google Drive as .zip using JSZip on Salesforce

The case:
On Salesforce platform I use Google Drive to store files (images for this case) with configured Apex Google Drive API Framework. So Google Drive API handles authToken and so on. I can upload and browse images in my application. In my case I want to select multiple files and download them in a single zip file. So far I'm trying to do that using JSZip and FileSaver libraries. With the same code below I can zip and download multiple files stored somewhere else with proper response header, but not from GDrive because of CORS error.
https://xxx.salesforce.com/contenthub/download/XXXXXXXXXX%3Afile%XXXXXX_XXXXXXXXX. No'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://xxx.visual.force.com' is therefore not allowed access. If I just click on this link, file starts to download.
Is there any way to configure GDrive to enable response header: Access-Control-Allow-Origin: * or Access-Control-Allow-Origin: https://*/mydomain.com somehow or I just have to use something else, maybe server side compression? Now I am using the download link provided by Apex Google Drive API (looks like this:
https://xxx.salesforce.com/contenthub/download/XXXXXXXXXXX%3Afile%XXXXXXXX), it works fine when used as src="fileURL" or when pasted directly to the browser. GDrive connector add 'accesToken' and so on.
My code:
//ajax request to get files using JSZipUtils
let urlToPromise = (url) =>{
return new Promise(function(resolve, reject) {
JSZipUtils.getBinaryContent(url, function (err, data) {
if(err) {
reject(err);
} else {
resolve(data);
}
});
});
};
this.downloadAssets = () => {
let zip = new JSZip();
//here 'selectedAssets' array of objects each of them has 'assetFiles'
//with fileURL where I have url. Download and add them to 'zip' one by one
for (var a of this.selectedAssets){
for (let f of a.assetFiles){
let url = f.fileURL;
let name = a.assetName + "." + f.fileType;
let filename = name.replace(/ /g, "");
zip.file(filename, urlToPromise(url), {binary:true});
}
}
//generate zip and download using 'FileSaver.js'
zip.generateAsync({type:"blob"})
.then(function callback(blob) {
saveAs(blob, "test.zip");
});
};
I also tried to change let url = f.fileURL to let url = f.fileURL + '?alt=media'; and &access_token=CURRENT_TOKEN added by GDrive connector.
this link handled by GRDrive connector so if I just enter it in browser it download the image. However, for multiple download using JS I got CORS error.
I think this feature is not yet supported. If you check the Download Files guide from Drive API, there's no mention of downloading multiple files at once. That's because you have to make individual API requests for each file. This is confirmed in this SO thread.
But that selected multiple files are convert into single zip file and download that single zip file which is possible with google drive API. So how can i convert them into single Zip File? please tell me.
According to me, just download all files and store them at temporary directory location and then add that directory to zip file and store that zip to physical device.
public Entity.Result<Entity.GoogleDrive> DownloadMultipleFile(string[] fileidList)
{
var result = new Entity.Result<Entity.GoogleDrive>();
ZipFile zip = new ZipFile();
try
{
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Download File",
});
FilesResource.ListRequest listRequest = service.Files.List();
//listRequest.PageSize = 10;
listRequest.Fields = "nextPageToken, files(id, name, mimeType, fullFileExtension)";
IList<File> files = listRequest.Execute().Files;
if (files != null && files.Count > 0)
{
foreach (var fileid in fileidList)
{
foreach (var file in files)
{
if (file.Id == fileid)
{
result.Data = new Entity.GoogleDrive { FileId = fileid };
FilesResource.GetRequest request = service.Files.Get(fileid);
request.ExecuteAsync();
var stream = new System.IO.FileStream(HttpContext.Current.Server.MapPath(#"~\TempFiles") + "\\" + file.Name, System.IO.FileMode.Create, System.IO.FileAccess.Write);
request.MediaDownloader.ProgressChanged += (IDownloadProgress progress) =>
{
switch (progress.Status)
{
case DownloadStatus.Downloading:
{
break;
}
case DownloadStatus.Completed:
{
break;
}
case DownloadStatus.Failed:
{
break;
}
}
};
request.Download(stream);
stream.Close();
break;
}
}
}
}
zip.AddDirectory(HttpContext.Current.Server.MapPath(#"~\TempFiles"), "GoogleDrive");
string pathUser = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string pathDownload = System.IO.Path.Combine(pathUser, "Downloads");
zip.Save(pathDownload + "\\GoogleDrive.zip");
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(HttpContext.Current.Server.MapPath(#"~\TempFiles"));
foreach (var file in di.GetFiles())
{
file.Delete();
}
result.IsSucceed = true;
result.Message = "File downloaded suceessfully";
}
catch (Exception ex)
{
result.IsSucceed = false;
result.Message = ex.ToString();
}
return result;
}
My previously published code works. Forgot to post a solution.
Just instead of using content hub link I started to use direct link to Google Drive and CORS issue was solved. Still not sure if CORS might be solved somehow at Salesforce side. Tried different setups with no luck.
Direct download link to GDrive works ok in my case. The only thing I had to change is the prefix to GDrive file ID.

document generation only works the first time

I'm using openxml in my HTML5 mobile app to generate word documents on the mobile device.
In general openxml works fine and straight forward, but I'm struggling with an annyoing problem.
The document generation only works the first time after I've started the app. This time I can open and view the document. Restart the app means:
- Redeploy from development machine
- Removing the app from the task pane (pushing aside; I assume the app is removed then?)
The second time I get the message the document is corrupted and I'm unable to view the file
UPDATE:
I can't reproduce this behaviour when I'm running the app connected to the remote debugger without having a breakpoint set. Doing it this way I always get a working document.
I doesn't make a difference wether I do any changes on the document or not. Simply open and saving reproduce this error.
After doing some research I've found that structure of the docx.zip file of the working and the corrupt file is the same. They also have the same file length. But in the corrupt docx there are some files I've found some files having a wrong/invalid CRC. See here an example when trying to get a corrupt file out of the zip. Other files are working as expected.
The properties for this file are->
(CRC in a working version is: 44D3906C)
Code for processing the doc-template:
/*
* Process the template
*/
function processTemplate(doc64, callback)
{
"use strict";
console.log("PROCESS TEMPLATE");
var XAttribute = Ltxml.XAttribute;
var XCData = Ltxml.XCData;
var XComment = Ltxml.XComment;
var XContainer = Ltxml.XContainer;
var XDeclaration = Ltxml.XDeclaration;
var XDocument = Ltxml.XDocument;
var XElement = Ltxml.XElement;
var XName = Ltxml.XName;
var XNamespace = Ltxml.XNamespace;
var XNode = Ltxml.XNode;
var XObject = Ltxml.XObject;
var XProcessingInstruction = Ltxml.XProcessingInstruction;
var XText = Ltxml.XText;
var XEntity = Ltxml.XEntity;
var cast = Ltxml.cast;
var castInt = Ltxml.castInt;
var W = openXml.W;
var NN = openXml.NoNamespace;
var wNs = openXml.wNs;
var doc = new openXml.OpenXmlPackage(doc64);
// add a paragraph to the beginning of the document.
var body = doc.mainDocumentPart().getXDocument().root.element(W.body);
var tpl_row = ((doc.mainDocumentPart().getXDocument().descendants(W.tbl)).elementAt(1).descendants(W.tr)).elementAt(2);
var newrow = new XElement(tpl_row);
doc.mainDocumentPart().getXDocument().descendants(W.tbl).elementAt(1).add(newrow);
// callback(doc);
var mod_file = null;
var newfile;
var path;
if (doc != null && doc != undefined ) {
mod_file = doc.saveToBlob();
// Start writing document
path = "Templates";
newfile = "Templates/Bau.docx";
console.log("WRITE TEMPLATE DOCUMENT");
fs.root.getFile("Templates/" + "MyGenerated.docx", {create: true, exclusive: false},
function(fileEntry)
{
fileEntry.createWriter(
function(fileWriter)
{
fileWriter.onwriteend = function(e) {
console.log("TEMPLATE DOCUMENT WRITTEN:"+e.target.length);
};
fileWriter.onerror = function(e) {
console.log("ERROR writing DOCUMENT:" + e.code + ";" + e.message);
};
var blobreader = new FileReader();
blobreader.onloadend = function()
{
fileWriter.write(blobreader.result); // reader.result contains the contents of blob as a typed array
};
blobreader.readAsArrayBuffer(mod_file);
},
null);
}, null);
};
Any ideas what I'm doing wrong?
Thanks for posting about the error. There were some issues with jszip.js that I encountered when I was developing the Open XML SDK for JavaScript.
At the following link, there is a sample javascript app that demonstrates generating a document.
Open XML SDK for JavaScript Demo
In that app you can save multiple DOCXs, one after another, and they are not corrupted.
In order to work on this issue, I need to be able to re-produce locally. Maybe you can take that little working web app and replace parts with your parts until it is generating invalid files?
Cheers, Eric
P.S. I am traveling and have intermittent access to internet. If you can continue the thread on OpenXmlDeveloper.org, then it will help me to answer quicker. :-)
What made it work for me, was changing the way of adding images (Parts) to the document. I was using the type "binary" for adding images to document. I changed this to "base64"
So I changed the source from:
mydoc.addPart( "/word/"+reltarget, openXml.contentTypes.png, "binary", fotodata ); // add Image Part to doc
to:
mydoc.addPart( "/word/"+reltarget, openXml.contentTypes.png, "base64", window.btoa(fotodata) ); // add Image Part to doc

file input does not update except in Chrome

I have a local program which writes a JSON object to a file so that a JavaScript can pick up its data and process it. The file is selected using an <input> object:
<form id = "getfiles">
<input type = "file" multiple id = "files" />
</form>
with the following JS function setInterval to repeat every 300ms. However, when the file changes, only Google Chrome reloads the file and processes the new content; I have to manually reselect the file on the page in IE 10 and Firefox 20.
function speakText()
{
var thefile = document.getElementById('files').files[0];
var lastChanged = thefile.lastModifiedDate;
var reader = new FileReader();
reader.onload = function(event)
{
var lcd = document.getElementById("last_change_date");
if (!lcd)
{
var spanLastChanged = document.createElement("span");
spanLastChanged.id = "last_change_date";
spanLastChanged.innerText = lastChanged;
console.log(lastChanged);
document.body.appendChild(spanLastChanged);
}
else
{
// compare lastChanged with last_change_date
var last_known_change = Date.parse(lcd.innerText);
// var last_known_change = Date.parse(thefile.lastModifiedDate);
if (last_known_change !== Date.parse(lastChanged))
{
console.log("Something is new since " + lcd.innerText);
var fileContent = event.target.result;
var commands = JSON.parse(fileContent);
handleJSON(fileContent);
lcd.innerText = lastChanged;
}
}
}
reader.readAsText(thefile, "UTF-8");
}
Firefox and IE are doing the right thing per spec: the File objects associated with a file input are supposed to be immutable snapshots of a file at the point when the File object was created. It's a known bug in WebKit/Blink that they just store a reference to the file's data, so that mutating the data will change what the File object sees.
In fact, the WebKit/Blink behavior is a privacy bug: when a user selects a file in a file input, they are giving a web page permission to read the data of the file at that time, not for all future versions of the file! Which is why the spec is written as it is.

How to parse a local XML file in Titanium?

My Resources folder contains an XML file. I need to parse it in Titanium. I have written the following code:
try {
var file = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory,'Translation.xml');
var xmltext = file.read().text;
var doc = Ti.XML.parseString(xmltext);
}
catch(e) {
alert(e);
Ti.API.info(e);
}
But I am getting the next error:
- result of expression 'file.read() is not an object
Any solution? Thanks!
Try to check if your file exists or not.
var file = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory,'Translation.xml');
if ( file.exists() ) {
var xmltext = file.read().text;
var doc = Ti.XML.parseString(xmltext);
}
It looks like the file can't be found on the system, that's why you are getting the error. Try putting the whole path as mentioned bellow. Example:
var file = Titanium.Filesystem.getFile("../Resources/tableWindows/CrossRef.xml");
Somebody with the same problem: http://developer.appcelerator.com/question/123246/xml-file-will-not-read

how to create an nsIFile object using URIs

I'm making extension for firefox, and I want to my extension open a file like "file:///home/blahblah/foo.txt" and then put content of this file in text area. Its easy with files "http://", but i cant do this with "file://"
when working with local files you have to really "load" them:
var file = Components.classes["#mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
file.initWithPath("/home/blahblah/foo.txt");
if ( file.exists() == false ) {
dup.value = “File does not exist”;
}
var istream = Components.classes["#mozilla.org/network/file-input-stream;1"]
.createInstance(Components.interfaces.nsIFileInputStream);
istream.init(file, 0x01, 4, null);
var fileScriptableIO = Components.classes["#mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
fileScriptableIO.init(istream);
// parse the xml into our internal document
istream.QueryInterface(Components.interfaces.nsILineInputStream);
var fileContent = "";
var csize = 0;
while ((csize = fileScriptableIO.available()) != 0)
{
fileContent += fileScriptableIO.read( csize );
}
fileScriptableIO.close();
istream.close();
fileContent contains the content as string
If you have the URI string for the file (rather than the local path or nsIFile object) then you can also use XMLHttpRequest to read the file's contents.

Categories

Resources