I am currently building an add on and I wanted to execute specific code on the first run. More specifically I want to click on my add on button, browse through my files and select an executable file. This browsing process should only be done on the first run as I want my button to "remember" to open this specific file after the first run.
jetpack.future.import("me");
var buttons = require('sdk/ui/button/action');
var button = buttons.ActionButton({
id: "execute-jar",
label: "Download Report",
icon: {
"16": "./icon-16.png",
"32": "./icon-32.png",
"64": "./icon-64.png"
},
onClick: handleClick
});
jetpack.me.onFirstRun(function(){ jetpack.notifications.show("Oh boy, I'm installed!");});
function handleClick(state) {
let {Cc, Ci} = require('chrome');
var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
file.initWithPath("C:\\Users\\QaziWa\\DownloadReportPPE.jar");
if(file.exists()){
file.reveal();
file.launch();
}
else {
console.log('Failed.');
}
}
I found this on MDN: https://developer.mozilla.org/en-US/docs/Archive/Mozilla/Jetpack/Meta/Me
However, this is something that was archived and when I tried this my code didn't succeed and got: "Message: ReferenceError: jetpack is not defined".
I'm pretty stumped at this point as I have looked at the few questions I could find that were relevant to what I want but I cannot figure out how to implement this much needed feature in my add-on. Could someone point me in the right direction or provide an example of some code that works?
EDIT: For clarity: I do not want to hardcode a path. I intend to add functionality that will allow users to select the file they wish to execute. My main question is how do I execute a certain block of code only on the first run?
The general case of having first-run code is that you use some sort of flag that is stored in a preference to indicate if you have run the code, or not. Preferences are what are used within Firefox to store simple data across application restarts. The flag can be any of multiple types (string, number, boolean, etc.). You just have to have a value which you can test to see if you have run your first-run code. The general case of this is discussed on MDN in Appendix B: Install and Uninstall Scripts, but that page is not SDK specific. When your add-on code starts running you then test to see if the flag indicates that you have already run your first-run code. If the flag indicates that you have not run the first-run code, you run that code and set the flag to indicate it has been run. You can modify this a bit to have code that is only run upon upgrading to a new version (just another flag), etc.
In this case, we also need to store a user chosen filename/path across Firefox restarts. Given that we already need to store that information, and it is what we need the first-run code to get, the validity of the chosenFilename
can also be used as the flag to run the first-run code. So, you store the full filename/path of the file chosen as a preference. If that preference does not contain a filename, then you run the selection logic/browse for the file (your first-run code).
In this instance, we also run the code to browse for a file if it is found that the file stored does not exist when we attempt to open it (e.g. the user deleted/moved the file). Obviously, you should also have a way for the user to manually start the file picker. Fortunately, the simple-prefs system takes care of that for us when we declare the type
as file
. A "Browse" button will then be displayed in the options dialog which the user can use to manually select a different file.
Something along the lines of:
let {Cc, Ci} = require('chrome');
let preferences = require("sdk/simple-prefs").prefs;
let winUtils = require("sdk/window/utils");
const nsIFilePicker = Ci.nsIFilePicker;
function chooseFilename(){
//If you only want .jar files then you would specify that in the filter(s):
preferences.chosenFilename = browseForFilePath(nsIFilePicker.filterAll);
//Just assume that it is valid. Should verify here that filename is valid.
}
function openChosenFilename() {
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
file.initWithPath(preferences.chosenFilename);
while(!file.exists()){
//The file we had is no longer valid. We need a valid filename so try choosing it
// again. Keep doing so until it actually exists.
chooseFilename();
file.initWithPath(preferences.chosenFilename);
}
return file;
}
//The following function was copied from promptForFile(), then modified:
//https://developer.mozilla.org/en-US/Add-ons/SDK/Tutorials/Creating_reusable_modules
function browseForFilePath(fileFilters) {
let filePicker = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
let recentWindow = winUtils.getMostRecentBrowserWindow();
filePicker.init(recentWindow, "Select a file", nsIFilePicker.modeOpen);
filePicker.appendFilters(fileFilters);
let path = "";
let status = filePicker.show();
if (status === nsIFilePicker.returnOK || status === nsIFilePicker.returnReplace) {
// Get the path as string.
path = filePicker.file.path;
}
return path; //"" if invalid
}
if(preferences.chosenFilename.length<5) {
//This is our first run code. We only run it if the length of the chosenFilename
// is less than 5 (which is assumed to be invalid).
// You can have any first run code here. You just need to have the
// preference you test for (which could be a string, boolean value, number, whatever)
// be set prior to exiting this if statement. In this specific case,
// it is a filename. Given that we also want to store the filename persistent
// across Firefox restarts we are checking for filename being stored as a preference
// instead of an additional flag that says we have already run this code.
chooseFilename();
}
let file = openChosenFilename();
file.reveal();
file.launch();
Your package.json also needs:
"preferences": [{
"name": "chosenFilename",
"title": "Filename that has been chosen",
"description": "A file the user has chosen",
"type": "file",
"value": ""
},