Hello to everyone here!
First, I searched for duplicate posts but I've not found something like my issue.
I'm making some tests (you will see some repeat in my code) to upload multiple files with bootstrap fileinput and I have some issues using the "delete" button on thumbnail previews.
The upload function is working fine, showing already uploaded images if exists with initialPreview option.
I'm trying to dynamically create the intialPreviewConfig option, and for the moment I don't know why it's not working (clicking the "delete" button give no actions at all, it's like the option is not present). However, when I manually add the intialPreviewConfig (not in a variable), it's magically working fine.
Sample javascript code (some of values are different in my true code) :
var e = 'http://localhost/foo/';
// Where other_prev is an array of img
// Where other_images_path is an array of paths to images
var other_prev = ['...'];
var other_images_path = ['...'];
var uploadOtherFileInput = function ($input) {
console.log(other_prev); // Okay : array with img tags
console.log(other_images_path); // Okay : array with urls to images
var id_to_upload;
// If id already exists
if($('#id').length) {
id_to_upload = $('#id').val();
} else {
id_to_upload = $('#id_to_upload').val();
}
// Construct initial preview config for deleting images
var initialPreviewConfig = [];
if(Array.isArray(other_images_path)) {
var xhr;
// Convert paths of images to blob objects
for(var i = 0; i < other_images_path.length; i++) {
(function (i) {
xhr = new XMLHttpRequest();
xhr.open('GET', other_images_path[i], true);
xhr.responseType = 'blob';
xhr.onload = function (ev) {
if (this.status == 200) {
var blobFile = this.response;
var splitted_path = other_images_path[i].split('/');
var img_name = splitted_path[splitted_path.length - 1];
blobFile.name = img_name;
initialPreviewConfig.push({
"caption": img_name,
"size": blobFile.size,
"url": e + 'ajax/delete_image',
"key": i + 1
});
}
};
xhr.send();
}).call(this, i);
}
}
// Console log is working
console.log(initialPreviewConfig);
// Making the bootstrap fileinput
// Working fine to show previews and upload new images
// Not working for initialPreviewConfig to delete images
$input.fileinput({
language: 'fr',
allowedFileExtensions: ["jpg", "jpeg", "png"],
uploadUrl: e + 'ajax/upload_image_sup',
uploadAsync: false, // Permet d'obtenir toutes les images en une fois et d'attendre la fin
minFileCount: 0,
maxFileCount: 20,
resizeImage: true,
showClose: false,
showCaption: false,
showBrowse: true,
showUpload: false,
showUploadedThumbs: false,
showPreview: true,
uploadExtraData: function () {
var out = {};
out.id = id_to_upload;
return out;
},
layoutTemplates: {
footer: '<div class="file-thumbnail-footer">\n' +
' <div class="file-caption-name" style="width:{width}">{caption}</div>\n' +
' {actions}\n' +
'</div>',
actions: '<div class="file-actions">\n' +
' <div class="file-footer-buttons">\n' +
' {delete} {zoom}' +
' </div>\n' +
' {drag}\n' +
' <div class="file-upload-indicator" title="{indicatorTitle}">{indicator}</div>\n' +
' <div class="clearfix"></div>\n' +
'</div>'
},
initialPreviewFileType: 'image',
initialPreview: other_prev,
initialPreviewConfig: initialPreviewConfig
});
// Okay it's a repeat thing but it's just for test purposes
if(Array.isArray(other_images_path)) {
var xhr;
for(var i = 0; i < other_images_path.length; i++) {
(function (i) {
xhr = new XMLHttpRequest();
xhr.open('GET', other_images_path[i], true);
xhr.responseType = 'blob';
xhr.onload = function (e) {
if (this.status == 200) {
var blobFile = this.response;
var splitted_path = other_images_path[i].split('/');
var img_name = splitted_path[splitted_path.length - 1];
blobFile.name = img_name;
// Add preview to stack for overwrite
$input.fileinput('addToStack', blobFile);
}
};
xhr.send();
}).call(this, i);
}
}
};
Console logs of other_prev and other_images_path are okay to create the previews.
Now the console log of the variable initialPreviewConfig is (width is not present but I removed it, no changes) :
[]
0: {caption: "xxx.jpeg", size: 381939, url: e + "ajax/delete_image", key: 1}
1: {caption: "yyy.jpeg", size: 381939, url: e + "ajax/delete_image", key: 2}
2: {caption: "zzz.jpeg", size: 381939, url: e + "ajax/delete_image", key: 3}
3: {caption: "aaa.jpeg", size: 381939, url: e + "ajax/delete_image", key: 4}
4: {caption: "bbb.JPG", size: 2442700, url: e + "ajax/delete_image", key: 5}
length: 5
__proto__: Array(0)
So everything seems to be OK... But that is not working for deleting.
However, if I manually create the config it's working "fine" (the ajax/delete_image route is not created at the moment but the click is OK and I get an error for this).
Example (values are not important here) :
...
initialPreviewFileType: 'image',
initialPreview: other_prev,
initialPreviewConfig: [
{caption: "xxx.jpg", size: 576237, width: "120px", url: e + "ajax/delete_image", key: 1},
{caption: "yyy.jpg", size: 576237, width: "120px", url: e + "ajax/delete_image", key: 2},
...
]
...
Can somebody help me with this issue or facing / faced the same ?
Tell me if you want more examples or a JSFiddle.
For this test, I'm using :
PHP 5.6 with framework CodeIgniter 3
Chrome 75
Bootstrap 3.3.7
jQuery 3.1.1
Bootstrap Fileinput 4.4.3
I also could use jQuery ($.ajax, $.get...) instead of XMLHttpRequest but it's not the question I think.
Thanks!
Good day!
Okay so it was as always an async problem.
It could be solved in many ways like promises or callback functions, but to keep consistent with the code I'm now creating the array of objects from the server before loading the page (like initialPreview thumbnails).
Sorry for the inconvenience!
Related
Code:
image_upload.js
function uploadAttachment(attachment) {
var file = attachment.file;
var form = new FormData;
form.append("Content-Type", file.type);
form.append("forum_post_photo[image]", file);
var xhr = new XMLHttpRequest;
xhr.open("POST", "/forum_post_photos.json", true);
xhr.setRequestHeader("X-CSRF-Token", Rails.csrfToken());
xhr.upload.onprogress = function(event){
var progress = event.loaded / event.total * 100;
attachment.setUploadProgress(progress);
}
xhr.onload = function(){
if (xhr.status == 201){
var data = JSON.parse(xhr.responseText);
return attachment.setAttributes({
url: data.image_url,
href: data.image_url
})
}
}
return xhr.send(form);
}
document.addEventListener("trix-attachment-add", function(event){
var attachment = event.attachment;
if (attachment.file){
console.log('new',attachment);
return uploadAttachment(attachment);
}
});
shrine.rb
require "shrine/storage/s3"
s3_options = {
bucket: Rails.application.credentials.aws[:bucket_name], # required
access_key_id: Rails.application.credentials.aws[:access_key_id],
secret_access_key: Rails.application.credentials.aws[:secret_access_key],
region: Rails.application.credentials.aws[:bucket_region],
}
Shrine.storages = {
cache: Shrine::Storage::S3.new(prefix: "cache",upload_options: { acl: "public-read" } , **s3_options),
store: Shrine::Storage::S3.new(prefix: "store",upload_options: { acl: "public-read" } ,**s3_options),
}
Shrine.plugin :activerecord
Shrine.plugin :presign_endpoint, presign_options: -> (request) {
filename = request.params["filename"]
type = request.params["type"]
{
content_disposition: "inline; filename=\"#{filename}\"", # set download filename
content_type: type, # set content type (required if using DigitalOcean Spaces)
content_length_range: 0..(10*1024*1024), # limit upload size to 10 MB
}
}
Shrine.plugin :restore_cached_data
trix-upload
require "shrine/storage/s3"
s3_options = {
bucket: Rails.application.credentials.aws[:bucket_name], # required
access_key_id: Rails.application.credentials.aws[:access_key_id],
secret_access_key: Rails.application.credentials.aws[:secret_access_key],
region: Rails.application.credentials.aws[:bucket_region],
}
Shrine.storages = {
cache: Shrine::Storage::S3.new(prefix: "cache",upload_options: { acl: "public-read" } , **s3_options),
store: Shrine::Storage::S3.new(prefix: "store",upload_options: { acl: "public-read" } ,**s3_options),
}
Shrine.plugin :activerecord
Shrine.plugin :presign_endpoint, presign_options: -> (request) {
filename = request.params["filename"]
type = request.params["type"]
{
content_disposition: "inline; filename=\"#{filename}\"", # set download filename
content_type: type, # set content type (required if using DigitalOcean Spaces)
content_length_range: 0..(10*1024*1024), # limit upload size to 10 MB
}
}
Shrine.plugin :restore_cached_data
trix-upload
function uploadAttachment(attachment) {
var file = attachment.file;
var form = new FormData;
form.append("Content-Type", file.type);
form.append("forum_post_photo[image]", file);
var xhr = new XMLHttpRequest;
xhr.open("POST", "/forum_post_photos.json", true);
xhr.setRequestHeader("X-CSRF-Token", Rails.csrfToken());
xhr.upload.onprogress = function(event){
var progress = event.loaded / event.total * 100;
attachment.setUploadProgress(progress);
}
xhr.onload = function(){
if (xhr.status == 201){
var data = JSON.parse(xhr.responseText);
return attachment.setAttributes({
url: data.image_url,
href: data.image_url
})
}
}
return xhr.send(form);
}
document.addEventListener("trix-attachment-add", function(event){
var attachment = event.attachment;
if (attachment.file){
console.log('new',attachment);
return uploadAttachment(attachment);
}
});
Long story short I am using trix for rich text on a forum, all models and controllers are working, I am attempting to direct_upload on with a drag and drop into the editor as shown here
but can't get the js right.
all other config is set direct from the documentation
Photos are being uploaded to my aws but all are expiring in a few mins
example: https://sprout-free-forum-photos.s3.amazonaws.com/store/de6271df193b0ae16e14c3297c58c363.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAINSUNFHRJEDP6TQA%2F20181027%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20181027T192116Z&X-Amz-Expires=900&X-Amz-SignedHeaders=host&X-Amz-Signature=a4c9da3b5933ca29954dfaf11e592543c69a5a7ad1d4dcd3b70747ef0a695c38
even with my bucket set to public read
any help would be great I am lost!
This is current site live and here is my full git
Experienced this problem today also.
Also using Shrine with AWS S3, and Trix in an old rails app.
What I noticed is that the images are present in the S3 server, its just the URLs that Trix is using that does not work.
After searching some other similar questions, ran into this: https://stackoverflow.com/a/51197576/2561325
The answer there is from one of the maintainer of the shrine gem. All you have to do is apply the public settings in your shrine initializer in config/initializers/shrine.rb.
My problem is fixed now, images used by Trix editor not expiring.
I'm still rather new to Appcelerator and using JSON files with JavaScript. I know I am parsing in the JSON file correctly, and breaking the data apart correctly, but for some reason the app can't seem to properly fetch the JSON data, and I invariably always get the onerror firing instead of the onload. Here is my code:
// Set the background color with no windows or tabs
Titanium.UI.setBackgroundColor('#000');
// Create the window
var win1 = Titanium.UI.createWindow({
title:'Challenge Window',
backgroundColor:'#fff',
});
// Store the image and its properties
var image = Titanium.UI.createImageView({
image: "https://myavantiservices.files.wordpress.com/2015/02/helloworld.gif",
height: 380,
width: 380,
center: 512,
top: -50
});
var table = Ti.UI.createTableView();
var tableData = [];
var json, line1, city, state, zip, appfile_id, id, body;
// Parse our JSON file using onload
var url = "https://raw.githubusercontent.com/JordanAshton/CodingChallenge/master/JSONtwitterOutput.txt";
var xhr = Ti.Network.createHTTPClient({
onload: function() {
json = JSON.parse(this.responseText);
for (var i = 0; i < json.things.length; i++){
var row = Ti.UI.createTableViewRow({
className: 'row',
objectName: 'row',
rowID: i,
height: 100,
borderColor: accentColor,
borderWidth: 1,
borderRadius: 5,
backgroundImage:'../images/opbg.png',
filter:json.data[i].line1 + "\n" + json.data[i].city + "," + json.data[i].state + " " + json.data[i].zip,
appfile_id: json.data[i].appfile_id,
message_id: json.data[i].id,
messagebody: json.data[i].body
});
tableData.push(row);
}
table.setData(tableData);
},
onerror: function(e) {
Ti.API.debug("STATUS: " + this.status);
Ti.API.debug("TEXT: " + this.responseText);
Ti.API.debug("ERROR: " + e.error);
alert('There was an error retrieving the remote data. Try again.');
},
timeout:5000
});
xhr.open("GET", url);
xhr.send();
// Add the image to the window and open the window
win1.add(image);
win1.add(table);
win1.open();
The JSON file I am parsing:
{"results":[
{"text":"#twitterapi https://code.google.com/archive/p/twitter-api/issues/353",
"to_user_id":396524,
"to_user":"TwitterAPI",
"from_user":"jkoum",
"metadata":
{
"result_type":"popular",
"recent_retweets": 109
},
"id":1478555574,
"from_user_id":1833773,
"iso_language_code":"nl",
"source":"twitter< /a>",
"profile_image_url":"http://s3.amazonaws.com/twitter_production/profile_images/118412707/2522215727_a5f07da155_b_normal.jpg",
"created_at":"Wed, 08 Apr 2009 19:22:10 +0000"},
... truncated ...],
"since_id":0,
"max_id":1480307926,
"refresh_url":"?since_id=1480307926&q=%40twitterapi",
"results_per_page":15,
"next_page":"?page=2&max_id=1480307926&q=%40twitterapi",
"completed_in":0.031704,
"page":1,
"query":"%40twitterapi"}
}
The root node of the JSON file you are parsing is "results"; but you are iterating up to json.things.length, which at that point should be 0, then no row is created and added to the tableView.
Also those json.data[i].<some_property> look like out of context.
Hth.
What I am trying to do is updating AngularJS variable from controller function and when I console its updated instantly but when I print it on View it updates after about 5-8 secs.
I try with both ng-model and curly braces but in both cases it after few seconds in view but in console its updated instantly.
I call uploadedMedia function in fine uploader callback and its working fine with console.log
$scope.UploadedMedia = function(){
console.log($scope.Album[0].Media.length);
$scope.UploadedMediaVal = $scope.Album[0].Media.length;
console.log($scope.Album[0].Media.length);
}
$scope.initFineUploader = function(){
var fcnt = 0;
var iuploader = new qq.FineUploaderBasic({
multiple: true,
autoUpload: true,
title: "Attach Photos",
button: $("li[data-type='uploadMediabutton']")[0],
request: {
endpoint: site_url + "api/uploadimage",
customHeaders: {
"Accept-Language": accept_language
},
params: {
Type: 'ratings',
unique_id: function() {
return '';
},
LoginSessionKey:LoginSessionKey,
DeviceType:'Native'
}
},
maxConnections : 50,
validation: {
acceptFiles: '.bmp,.jpeg,.jpg,.gif,.png',
allowedExtensions: ['bmp','jpeg', 'jpg', 'gif', 'png', 'JPEG', 'JPG', 'GIF', 'PNG'],
sizeLimit: 4194304 // 40mb
},
callbacks: {
onUpload: function(id, fileName) {
$scope.Album[0].Media.push({MediaGUID:'',ImageName:'',Caption:'',MediaType:'Image',VideoLength:'',ConversionStatus:'',IsLoader:'1',FileName:fileName});
$scope.UploadedMedia();
$('.rating-submit').attr('disabled','disabled');
fcnt++;
},
onProgress: function(id, fileName, loaded, total) {
$scope.Uploading = 1;
},
onComplete: function(id, fileName, responseJSON) {
fcnt--;
if (responseJSON.Message == 'Success') {
$($scope.Album[0].Media).each(function(mk,mv){
if(mv.FileName == fileName){
$scope.Album[0].Media[mk]['MediaGUID'] = responseJSON.Data.MediaGUID;
$scope.Album[0].Media[mk]['ImageName'] = responseJSON.Data.ImageName;
$scope.Album[0].Media[mk]['IsLoader'] = 0;
}
});
var fNameExt = fileName.substr(fileName.lastIndexOf('.') + 1);
$('li[data-filename="'+fileName+'"]').remove();
setTimeout(function(){
$('li[data-filename="'+fileName+'"] .m-laoder').remove();
},1000);
} else {
$('li[data-filename="'+fileName+'"]').remove();
}
if(fcnt <= 0){
$scope.Uploading = 0;
$('.rating-submit').removeAttr('disabled');
$('.attached-media-list li.media-loader').remove();
}
$scope.UploadedMedia();
},
onValidate: function(b) {
if($scope.Album[0].Media.length>=10){
showResponseMessage('You can upload maximum 10 images, please delete any old image to upload new one.','alert-danger');
return false;
}
var validExtensions = ['bmp','jpeg', 'jpg', 'gif', 'png', 'JPEG', 'JPG', 'GIF', 'PNG']; //array of valid extensions
var fileName = b.name;
var fileNameExt = fileName.substr(fileName.lastIndexOf('.') + 1);
if ($.inArray(fileNameExt, validExtensions) == -1) {
showResponseMessage('Allowed file types only bmp, jpeg, jpg, gif and png.','alert-danger');
return false;
}
if (b.size > 4194304) {
showResponseMessage('Image file should be less than 4 MB','alert-danger');
}
},
onError: function(){
$('.attached-media-list li.media-loader:last-of-type').remove();
}
}
});
}
<div>
{{UploadedMediaVal}}
<span ng-bind="UploadedMediaVal"></span>
</div>
Write $scope.$apply();, after modifying your variable.
How do you invoke SomeOtherFunction? Is it triggered in the angular digest phase or by a dom event. In the second case you have to wrap the commands with a $scope. $apply (){}
Here is sample demo you code that may help you http://dojo.telerik.com/UmIvO
But I think is it possible to share you album array to test
I have tested it is giving immediate response could you please check with your album array. So that may help you out.
I'm working on an app for Firefox OS < 1.3 to set your songs as ringtones.
The repo https://github.com/Mte90/RingTone-Picker-for-FirefoxOS and the file with the problem is script.js
In the line https://github.com/Mte90/RingTone-Picker-for-FirefoxOS/blob/master/script.js#L73 the path it's correct like "/emmc/audio.ogg" but the audio player return core error 4.
This problem is for a wrong path but the path is correct!
If i add on the line 74 console.log(player.src) return a path like "app://strangenumberhash/emmc/audio.ogg".
I have no absolutely idea how to fix this problem.
The app protocol is not allowed to be used to reference audio/video files within a packaged app. I believe this is a security restriction is to prevent cross app content reading. You need to either use an audio tag in your HTML or use an XMLHttpRequest. Something like the following (video example):
var xhr = new XMLHttpRequest();
xhr.open('GET', 'myvid.ogg');
xhr.responseType = 'blob';
xhr.send();
xhr.onload = function() {
videoblob = new Blob([xhr.response], { type: 'video/ogg' });
var openingVideo = new MozActivity({
name: "open",
data: {
type: [
"video/webm",
"video/mp4",
"video/3gpp",
"video/mkv",
"video/ogg"
],
blob: videoblob
}
});
};
xhr.onerror = function() {
console.log('Error loading test video', xhr.error.name);
};
If the file is on the SDCard you have a couple of options:
One you could just use a pick activity and let the user locate it:
var act = new MozActivity({
name: 'pick',
data: {
type: 'audio/ogg'
}
});
or you can set the readwrite permission on the sdcard in the manifest and read it manually and play it with the audio tag or with a open activity (very little error checking).
var sdcard = navigator.getDeviceStorage('sdcard');
//assumes sample.ogg is located at the top of the sdcard
var request = sdcard.get("sample.ogg");
request.onsuccess = function () {
var file = this.result;
console.log("Get the file: " + file.name);
var mysrc = URL.createObjectURL(file);
var audio1 = new Audio();
audio1.onerror = function(e) {
console.log(" error playing file ");
}
audio1.src = mysrc;
audio1.type = "video/ogg";
console.log( "audio src " + audio1.src);
audio1.play();
URL.revokeObjectURL(url);
}
request.onerror = function () {
console.warn("Unable to get the file: ");
}
There are so much topics about download files with addon sdk, but I try to deal with the problem from since few days and still I got nothing...
Ok, I work on AddOn Builder online on FireFox and I want get something like this:
Link with pdf -> I click on this by right mouse button -> chosing the "Get PDF" -> pdf is downloading to f.e. "c:\temp\"
I founded many of example codes, but every code doesn't work.
I don't have any errors, everything built ok, but when I clicked the "Get PDF" nothing saved in "c:\temp\" folder.
Every code is similar so i paste two of them:
This is my exports.main = function()
const { Cc, Ci, Cu } = require('chrome');
var contextMenu = require("sdk/context-menu");
var menuItem = contextMenu.Item({
label: "Get PDF",
context: contextMenu.SelectorContext(" a[href *= '.pdf']"),
contentScript: 'self.on("click", function (node, data) {' +
' self.postMessage("test.pdf", "link to pdf");' +
'});',
onMessage: function (sLocalFileName, sRemoteFileName)
{
var saveToDirectory = 'C:\\temp\\';
//var chrome = require("chrome");
var oIOService = Cc["#mozilla.org/network/io-service;1"].getService(Ci.nsIIOService)
var oLocalFile = Cc["#mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
oLocalFile.initWithPath(saveToDirectory + sLocalFileName);
var oDownloadObserver = {onDownloadComplete: function(nsIDownloader, nsresult, oFile) {console.log('download complete...')}};
var oDownloader = Cc["#mozilla.org/network/downloader;1"].createInstance();
oDownloader.QueryInterface(Ci.nsIDownloader);
oDownloader.init(oDownloadObserver, oLocalFile);
var oHttpChannel = oIOService.newChannel(sRemoteFileName, "", null);
oHttpChannel.QueryInterface(Ci.nsIHttpChannel);
oHttpChannel.asyncOpen(oDownloader, oLocalFile);
}
});
Second:
const { Cc, Ci, Cu } = require('chrome');
var contextMenu = require("sdk/context-menu");
var menuItem = contextMenu.Item({
label: "Get PDF",
context: contextMenu.SelectorContext(" a[href *= '.pdf']"),
contentScript: 'self.on("click", function (node, data) {' +
' self.postMessage(node.href);' +
'});',
onMessage: function (links)
{
// download from: aURLToDownload
var downloadURI = Cc["#mozilla.org/network/io-service;1"].getService(Ci.nsIIOService).newURI(links, null, null);
// download destination
var outputFile = Cc["#mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
outputFile.initWithPath("c:\\temp\\1.pdf");
var persist = Cc["#mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
persist.saveURI(downloadURI, null, null, null, "", outputFile);
}
});
Please help!
Alright I had a similar issue when I was playing around with this.. My code is very close to what you have but I added a few helpful steps.. First I get the directory path from preferences. Then I actually create the directory if it does not exist.. In my case I was creating sub-directories as well, you may not need it but just in case.
function DownloadFile(sdirectory, sLocalFileName, sRemoteFileName)
{
var baseDirectory = require('sdk/simple-prefs').prefs['downloadpath'] + "\\";
var saveToDirectory = baseDirectory + sdirectory + '\\';
var oLocalDir = chrome.Cc["#mozilla.org/file/local;1"].createInstance(chrome.Ci.nsILocalFile);
oLocalDir.initWithPath(saveToDirectory);
if(!oLocalDir.exists())
{
oLocalDir.create(1,777);
}
var oIOService = chrome.Cc["#mozilla.org/network/io-service;1"].getService(chrome.Ci.nsIIOService)
var oLocalFile = chrome.Cc["#mozilla.org/file/local;1"].createInstance(chrome.Ci.nsILocalFile);
oLocalFile.initWithPath(saveToDirectory + sLocalFileName);
var oDownloadObserver = {onDownloadComplete: function(nsIDownloader, nsresult, oFile)
{
console.log('download complete...');
}};
var oDownloader = chrome.Cc["#mozilla.org/network/downloader;1"].createInstance();
oDownloader.QueryInterface(chrome.Ci.nsIDownloader);
oDownloader.init(oDownloadObserver, oLocalFile);
var oHttpChannel = oIOService.newChannel(sRemoteFileName, "", null);
oHttpChannel.QueryInterface(chrome.Ci.nsIHttpChannel);
oHttpChannel.asyncOpen(oDownloader, oLocalFile);
}
First thing you should do if you have not already, go to about:config and change devtools.errorconsole.enabled to true.
Next add a log statement to the beginning of your download event.. I would actually suggest you break out that method and just call the DownloadFile method in you event.
The most important thing I found out I had to do was sanitize my file name.. with
var file = "somefilename"
file = file.replace(/[/\\:?<>|\"]+/g, "");
If the file name with illegal characters, or a directory path wrong at all I had the same issues.
So I would make your code like..
....
onMessage: function (filename, fileURL)
{
console.log("Message Event, filename: " + filename +" URL: " +fileURL);
DownloadFile(filename,fileURL);
}});
function DownloadFile(sLocalFileName, sRemoteFileName)
{
var baseDirectory = require('sdk/simple-prefs').prefs['downloadpath'] + "\\";
var saveToDirectory = baseDirectory;
var oLocalDir = chrome.Cc["#mozilla.org/file/local;1"].createInstance(chrome.Ci.nsILocalFile);
oLocalDir.initWithPath(saveToDirectory);
if(!oLocalDir.exists())
{
oLocalDir.create(1,777);
}
var oIOService = chrome.Cc["#mozilla.org/network/io-service;1"].getService(chrome.Ci.nsIIOService)
var oLocalFile = chrome.Cc["#mozilla.org/file/local;1"].createInstance(chrome.Ci.nsILocalFile);
oLocalFile.initWithPath(saveToDirectory + sLocalFileName);
var oDownloadObserver = {onDownloadComplete: function(nsIDownloader, nsresult, oFile) {console.log('download complete...')}};
var oDownloader = chrome.Cc["#mozilla.org/network/downloader;1"].createInstance();
oDownloader.QueryInterface(chrome.Ci.nsIDownloader);
oDownloader.init(oDownloadObserver, oLocalFile);
var oHttpChannel = oIOService.newChannel(sRemoteFileName, "", null);
oHttpChannel.QueryInterface(chrome.Ci.nsIHttpChannel);
oHttpChannel.asyncOpen(oDownloader, oLocalFile);
}
EDIT :
Forgot to mention you need this in your package.json file, to be able to set and retrieve the preferences.
"preferences": [{
"name": "downloadpath",
"title": "Download Path",
"description": "Select a directory to download",
"type": "directory"
}]