Downloading files with a Firefox addon - firefox

I'm new to Firefox addon development, and it's going well so far, but I'm stuck on how to, essentially, download a file from the Web, given a URI, and save it to disk. Mozilla's MDN documentation has information on how to upload files, but the downloading files section is empty and yet to be written. Sadly, I haven't found any documentation which describes how to do this.
Does anyone know of relevant documentation on how to do this?
The old Facebook Photo Album Downloader addon uses this function call in its overlay JavaScript:
saveURL(images[i].replace(/\/s/g, "/n"), null, null, false, true, null);
Obviously, the first argument is the URI to request. The saveURL function isn't defined anywhere, so I assume it's an extension API function. I have tried it in my new addon, and it does work. I would, however, like to know what the other arguments mean.

The standard way to do this is with nsIWebBrowserPersist:
var persist =
Cc["#mozilla.org/embedding/browser/nsWebBrowserPersist;1"].
createInstance(Ci.nsIWebBrowserPersist);
persist.saveURI(serverURI, null, null, null, "", targetFile);
See https://developer.mozilla.org/en/Code_snippets/Downloading_Files for more info.

There actually is some MDN documentation on this: https://developer.mozilla.org/en/Code_snippets/Downloading_Files.

Here's an easy copy/paste option for anyone looking for a quick solution without any further messing about. Put it in your main.js and change the filename, directory and url.
function DownloadFile(sLocalFileName, sRemoteFileName)
{
var saveToDirectory = 'C:\\Users\\louis\\downloads\\';
var chrome = require("chrome");
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);
}
DownloadFile("saveAsThis.mp3","http://domain.com/file.mp3");

As of 2015, the APIs for managing (starting, stopping, etc.) downloads have changed since this question was answered. The new APIs are (links to documentation on MDN):
Downloads.jsm
Download
DownloadTarget
PlacesUtils.There is good info at paa's answer to the question: API to modify Firefox downloads list

Related

How do you effectively solve node module issues when google isn't providing many answers?

I received this issue and google isn't providing many case-specific examples to work from. Can anyone decode this? I am not really sure what the main issue is.
I have followed the file path of the first issue to cjs.js file but there isn't much there
"use strict";
const loader = require("./index");
module.exports = loader.default;
And the file path of the second issue leads me to this
var correctedContent = params.removeCR && (os.EOL !== '\\r') ?
sourceContent.replace(ORPHAN_CR_REGEX, ' $1') :
sourceContent;
Github link for context.

Google sheets IMPORTXML fails for ASX data

I am trying to extract the "Forward Dividend & Yield" value from https://finance.yahoo.com/ for multiple companies in different markets, into Google Sheets.
This is successful:
=IMPORTXML("https://finance.yahoo.com/quote/WBS", "//*[#id='quote-summary']/div[2]/table/tbody/tr[6]/td[2]")
But this fails with #N/A:
=IMPORTXML("https://finance.yahoo.com/quote/CBA.AX", "//*[#id='quote-summary']/div[2]/table/tbody/tr[6]/td[2]")
I cannot work out what needs to be different for ASX ticker codes, why does CBA.AX cause a problem?
Huge thanks for any help
When I tested the formula of =IMPORTXML("https://finance.yahoo.com/quote/CBA.AX", "//*"), an error of Error Resource at url not found. occurred. I thought that this might be the reason of your issue.
But, fortunately, when I try to retrieve the HTML from the same URL using Google Apps Script, the HTML could be retrieved. So, in this answer, I would like to propose to retrieve the value using the custom function created by Google Apps Script. The sample script is as follows.
Sample script:
Please copy and paste the following script to the script editor of Google Spreadsheet and save it. And, please put a formula of =SAMPLE("https://finance.yahoo.com/quote/CBA.AX") to a cell. By this, the value is retrieved.
function SAMPLE(url) {
const res = UrlFetchApp.fetch(url).getContentText().match(/DIVIDEND_AND_YIELD-value.+?>(.+?)</);
return res && res.length > 1 ? res[1] : "No value";
}
Result:
When above script is used, the following result is obtained.
Note:
When this script is used, you can also use =SAMPLE("https://finance.yahoo.com/quote/WBS").
In this case, when the HTML structure of the URL is changed, this script might not be able to be used. I think that this situation is the same with IMPORTXML and the xpath. So please be careful this.
References:
Custom Functions in Google Sheets
Class UrlFetchApp
An other solution is to decode the json contained in the source of the web page. Of course you can't use importxml since the web page is built on your side by javascript and not on server's side. You can access data by this way and get a lot of informations
var source = UrlFetchApp.fetch(url).getContentText()
var jsonString = source.match(/(?<=root.App.main = ).*(?=}}}})/g) + '}}}}'
i.e. for what you are looking for you can use
function trailingAnnualDividendRate(){
var url='https://finance.yahoo.com/quote/CBA.AX'
var source = UrlFetchApp.fetch(url).getContentText()
var jsonString = source.match(/(?<=root.App.main = ).*(?=}}}})/g) + '}}}}'
var data = JSON.parse(jsonString)
var dividendRate = data.context.dispatcher.stores.QuoteSummaryStore.summaryDetail.trailingAnnualDividendRate.raw
Logger.log(dividendRate)
}

Problem with Objective-C marshalling an "optionals" property in Nativescript

I'm building a NativeScript plugin for iOS to integrate a card payment terminal as an external accessory. It is almost done, and working, but I have problem with passing one argument called "optionals". This is the whole code I'm trying to implement. It's the payworks framework for a Miura terminal. http://www.payworks.mpymnt.com/node/143
MPTransactionParameters *tp = [MPTransactionParameters chargeWithAmount:[NSDecimalNumber decimalNumberWithString:#"5.00"]
currency:MPCurrencyEUR
optionals:^(id<MPTransactionParametersOptionals> _Nonnull optionals) {
optionals.subject = #"Bouquet of Flowers";
optionals.customIdentifier = #"yourReferenceForTheTransaction";
}];
I cannot find a way of sending this "optionals" function.
In the generate typing metadata I see the MPTransactionParametersOptionals is a #protocol, but still don't know how to use it here as a parameter.
This is my current javascript code for the block
const tp = MPTransactionParameters.chargeWithAmountCurrencyOptionals(
amount,
MPCurrencyEUR,
function (optionals) {
console.log(optionals); //logs the newly created MPTransactionParameters instance, with set amount and currency properties, but cannot touch or set the optional properties.
}
);
The 3rd parameter of chargeWithAmountCurrencyOptionals() should be a function, but I'm doing it wrong, and searched everywhere in google how to do it but no success. I'm already trying for 2 days.
It is working, when the 3rd parameter is null, but I need the set the optional properties.
EDIT: adding the metadata. There are a lot of typings for MPtransactionParameters, so I decided to give you the whole file so you can search.
https://drive.google.com/open?id=1kvDoXtGbCoeCT20b9_t2stc2Qts3VyQx
EDIT2: Adding the typings:
https://drive.google.com/open?id=1lZ3ULYHbX7DXdUQMPoZeSfyEZrjItSOS

Calling checkCurrentDictionary() from addon crashes FF - why?

I'm tyring to call the method checkCurrentDictionary() of nsIEditorSpellCheck from within an add-on. The relevant code I use is:
var editorSpellCheck = Cc["#mozilla.org/editor/editorspellchecker;1"].createInstance(Ci.nsIEditorSpellCheck);
editorSpellCheck.checkCurrentDictionary();
This immediately crashes the Fx. What is going wrong here?
So this probably has something to do with the fact that nsIEditorSpellCheck is not a scriptable interface.
Basically, a scriptable interface is one that can be used from JavaScript.
If you want to access the spell check service you can do something like:
let editor = editableElement.editor;
if (!editor) {
let win = editableElement.ownerDocument.defaultView;
editor = win.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIWebNavigation).
QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIEditingSession).
getEditorForWindow(win);
}
if (!editor)
throw new Error("Unable to find editor for element " + editableElement);
(The above is from http://dxr.mozilla.org/mozilla-central/source/editor/AsyncSpellCheckTestHelper.jsm which is MPL).
Then you can use the InlineSpellCheck.jsm to do some crazy stuff.
I'm not sure what you want to do though, so perhaps you should ask that more specific question as a new question.

Add download to Firefox via Firefox extension

This is my first Firefox extension which I'm developing with addon-builder [builder.addons.mozilla.org/] .
My question is simple but after trying many things, for many days, I'm unable to get results.
I want to know: How to add a file download to Firefox downloader??
I've a url like: http:// example.com/file.zip and a file location like: D:\myFolder.
I want to add this download via my firefox extension.
The things which I've searched are:
https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIWebBrowserPersist#saveURI%28%29
https://developer.mozilla.org/en-US/docs/Code_snippets/Downloading_Files
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
const WebBrowserPersist = Components.Constructor("#mozilla.org/embedding/browser/nsWebBrowserPersist;1",
"nsIWebBrowserPersist");
var persist = WebBrowserPersist();
var targetFile = Services.dirsvc.get("Desk", Ci.nsIFile);
targetFile.append("file.bin");
// Obtain the privacy context of the browser window that the URL
// we are downloading comes from. If, and only if, the URL is not
// related to a window, null should be used instead.
var privacy = PrivateBrowsingUtils.privacyContextFromWindow(urlSourceWindow);
persist.persistFlags = persist.PERSIST_FLAGS_FROM_CACHE
| persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
persist.saveURI(uriToSave, null, null, null, "", targetFile, privacy);
Can you just gimme a start from where I should get the easiest possible download function.
Components.utils.import("resource://gre/modules/Services.jsm");
var {downloads}=Services;
downloads.addDownload(/*parameters*/); //see documentation for parameters.
Documentation for addDownload: nsIDownloadManager#addDownload()
Documentation and directory for the wide range of services provided by Services.jsm: Services.jsm

Resources