Create XPI package with the Add-on SDK? - javascript

I got task to write an add-on for Firefox which will add an div element to existing page. I downloaded Add-on SDK and wrote a main.js file that looks like this:
var data = require("sdk/self").data;
require("sdk/tabs").on("ready", ExecuteAd);
function ExecuteAd(tab) {
if ( tab.url.indexOf("some url checking") > -1 ) {
var image = "http://www.lavasoft.com/img/product_icons/aaw11/free.png";
var link = "http://www.google.me";
tab.attach({
contentScriptFile: data.url("myscript.js"),
contentScript: "appendFunc('"+image+"', '"+link+"');"
//contentScript: "alert('Works');"
});
}
}
When I execute command cfx run it starts Firefox and if I go to specific web pages this script works. But when I create XPI file with cfx xpi and then click on Firefox and open that file it installs my add-on but now when I go to same web pages I gave been before add-on does not work. I have this external Javascript file which is stored in folder 'data'.
appendFunc is in myscript.js file.
How to make my extension work in production environment not just testing environment? I think that main problem is that it does not find this data/myscript.js (does it include in .xpi file?)

Don't mix contentScript and contentScriptFile. Also, you cannot know what of both is loaded first.
Instead load your script, and communicate using port.
main.js
var data = require("sdk/self").data;
require("sdk/tabs").on("ready", ExecuteAd);
function ExecuteAd(tab) {
var image = "http://www.lavasoft.com/img/product_icons/aaw11/free.png";
var link = "http://www.google.me";
var worker = tab.attach({
contentScriptFile: data.url("myscript.js")
});
worker.port.emit("showAd", {image: image, link: link});
}
myscript.js
self.port.on("showAd", function(data) {
console.log("showing ad", data.link, data.image);
});
Also, it sounds like PageMod would be a better choice for what you're doing.
PS: Also consult the Add-on Policies if you're planning to host on the addons.mozilla.org website. The policies e.g. prohibit injecting ads that a) aren't clearly marked as such and b) where the user did not opt-in prior to that.

Related

ReferenceError while using sdk/tabs in firefox webextension

This is my first time learning to build a firefox addon. I want store all the open tabs in a window and for that I require sdk/tabs.
Here is my js file:
/*
Given the name of a beast, get the URL to the corresponding image.
*/
debugger;
var tabs = require("sdk/tabs");
function beastNameToURL(beastName) {
switch (beastName) {
case "Save Session":
debugger;
for (let tab of tabs)
console.log(tab.url);
return;
case "Load Session":
debugger;
return chrome.extension.getURL("beasts/snake.jpg");
case "Turtle":
return chrome.extension.getURL("beasts/turtle.jpg");
}
}
/*
Listen for clicks in the popup.
If the click is not on one of the beasts, return early.
Otherwise, the text content of the node is the name of the beast we want.
Inject the "beastify.js" content script in the active tab.
Then get the active tab and send "beastify.js" a message
containing the URL to the chosen beast's image.
*/
document.addEventListener("click", function(e) {
if (!e.target.classList.contains("btn")) {
return;
}
var chosenBeast = e.target.textContent;
var chosenBeastURL = beastNameToURL(chosenBeast);
chrome.tabs.executeScript(null, {
file: "/content_scripts/beastify.js"
});
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {beastURL: chosenBeastURL});
});
});
When I reach the var tabs = require("sdk/tabs") line I get a Reference error.
Github : https://github.com/sagar-shah/Session-manifest
Kindly let me know how do I resolve this error. This being my first time with add-ons I am completely lost.
Thanks in advance.
Update:
Tried to declare it globally in the js file. Now I am getting undefined error for tabs.
Update2:
I was mixing up development using sdk and webextensions as pointed out by #matagus. I have decided to go with development using the webextensions. Link to the new repository has been updated.
The error is on package.json line 6: you're telling to the addon sdk that the main file of your addon is manage.json. According to [the docs] the value of main should be:
A string representing the name of a program module that is located in one of the top-level module directories specified by lib. Defaults to "index.js".
So you need to change its value to index.js.
Besides that, I think you're missing a difference between Firefox addon built using the addon-sdk (which do not have a ´manifest.json´ and that you build using jpm tool) and the new WebExtensions which do require you to write a ´manifest.json´ like the one already have.
UPDATE:
Again: you're missing the difference between WebExtensions and SDK-based addons. Now you made a WebExtension but you're trying to use the SDK. It isn't possible. Just use chrome.tabs directly instead of trying to import it from the sdk (var tabs = require("sdk/tabs");).

Automate daily csv file download from website button click

I would like to automate the process of visiting a website, clicking a button, and saving the file. The only way to download the file on this site is to click a button. You can't navigate to the file using a url.
I have been trying to use phantomjs and casperjs to automate this process, but haven't had any success.
I recently tried to use brandon's solution here
Grab the resource contents in CasperJS or PhantomJS
Here is my code for that
var fs = require('fs');
var cache = require('./cache');
var mimetype = require('./mimetype');
var casper = require('casper').create();
casper.start('http://www.example.com/page_with_download_button', function() {
});
casper.then(function() {
this.click('#download_button');
});
casper.on('resource.received', function (resource) {
"use strict";
for(i=0;i < resource.headers.length; i++){
if(resource.headers[i]["name"] == "Content-Type" && resource.headers[i]["value"] == "text/csv; charset-UTF-8;"){
cache.includeResource(resource);
}
}
});
casper.on('load.finished', function(status) {
for(i=0; i< cache.cachedResources.length; i++){
var file = cache.cachedResources[i].cacheFileNoPath;
var ext = mimetype.ext[cache.cachedResources[index].mimetype];
var finalFile = file.replace("."+cache.cacheExtension,"."+ext);
fs.write('downloads/'+finalFile,cache.cachedResources[i].getContents(),'b');
}
});
casper.run();
I think the problem could be caused by my cachePath being incorrect in cache.js
exports.cachePath = 'C:/Users/username/AppData/Local/Ofi Labs/PhantomJS';
Should I be using something in adition to the backslashes to define the path?
When I try
casperjs --disk-cache=true export_script.js
Nothing is downloaded. After a little debugging I have found that cache.cachedResources is always empty.
I would also be open to solutions outside of phantomjs/casperjs.
UPDATE
I am not longer trying to accomplish this with CasperJS/PhantomJS.
I am using the chrome extension Tampermonkey suggested by dandavis.
Tampermonkey was extremely easy to figure out.
I installed Tampermonkey, navigated to the page with the download link, and then clicked New Script under tampermonkey and added my javascript code.
document.getElementById("download_button").click();
Now every time I navigate to the page in my browser, the file is downloaded. I then created a batch script that looks like this
set date=%DATE:~10,4%_%DATE:~4,2%_%DATE:~7,2%
chrome "http://www.example.com/page-with-dl-button"
timeout 10
move "C:\Users\user\Downloads\export.csv" "C:\path\to\dir\export_%date%.csv"
I set that batch script to run nightly using the windows task scheduler.
Success!
Your button most likely issues a POST request to the server.
In order to track it:
Open Network tab in Chrome developer tools
Navigate to the page and hit the button.
Notice which request led to file download. Right click on it and copy as cURL
Run copied cURL
Once you have cURL working you can schedule downloads using cron or Task Scheduler depending on operation system you are using.

Opening a specific url when a Firefox addon has been installed

I am using the Firefox SDK to create an add-on. I would like a specific webpage to be open once that add-on is successfully installed. I created a module to attempt to do so:
var tabs = require("sdk/tabs");
exports.main = function (options, callbacks) {
if (options.loadReason === 'install') {
tabs.open("https://www.google.com");
}
};
exports.onUnload = function (reason) {
if (reason === 'uninstall') {
tabs.open("https://www.google.com");
}
};
I then require this script in my main.js file (handlers.js is the name of the above script):
require("handlers.js");
However, this script does not execute -- whether during installation or uninstallation. I have tried the following links for help, but I don't seem to be able to solve my issue:
https://developer.mozilla.org/en-US/Add-ons/SDK/Tutorials/Listening_for_load_and_unload
Opening a page after Firefox extension install
The solution for this was repackaging the add-on with the package.json and it worked except for the onUnload function which has a bug and uninstall is never called as a reason and as such I had to use "disable" as the reason to check for and it worked!.
For more on the bug refer to: https://developer.mozilla.org/en-US/Add-ons/SDK/Tutorials/Listening_for_load_and_unload

Access DOM of a web site via google packaged app

my aim is to write an app for chrome which communicates details of the DOM of a web page via xhttprequest to a local web server.
In order to access the dom of a web site one would usually use tabs in combination with a content script like this:
chrome.tabs.create({ url: "www.example.com" });
chrome.tabs.executeScript(null, {file: "content_script.js"});
And then use the messaging system to communicate the stuff to the background script.
Unfortunately when I do that, I need to add "tabs" permission to the manifest which is not allowed for packaged apps, only for extensions. I need to implement a packaged app because in a usual extension, no socket connection is allowed (which I need at some time).
I also tried what is suggested here: How to write content in child window using chrome packaged app?
However,
chrome.app.window.create
Does only work for local html files, not for external websites.
So my question again:
(how) is it possible in a packaged app to access the dom of a website?
You could try using a <webview> for Chrome apps and inject custom scripts via the executeScript method.
Remember to specify the "webview" permission in your manifest file.
Thank you very much! I did it exactly as you said, Joseph Portelli.
The code:
main.js
chrome.app.window.create('webview.html', {},
function (createdWindow) {
var win = createdWindow.contentWindow;
win.onload = function () {
var webview = win.document.querySelector('#webview');
webview.setAttribute("src", "http://www.example.com");
webview.addEventListener("contentload", function () {
webview.executeScript({file: "content_script.js"}, function(result) {});
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if(request.dom) {
plugin.sendDom(request.dom, request.browser);
}
});
});
}
});
webview.html
<!doctype html>
<html>
<body>
<webview id="webview" style="height:100%;width:100%"/>
</body>
</html>
content_script.js
...
var body = document.getElementsByTagName("body")[0];
var dom = {root: domTraverser.recurseDomChildren(body)};
chrome.runtime.sendMessage({dom:dom, browser: getBrowserName()});

Firefox SDK page-mod onAttach event not firing even though code is injected

I'm developing a firefox extension using the addon SDK 1.15 and part of it should inject a script into http://linustechtips.com/*. This is an extract from my code:
var pageMod = require("sdk/page-mod");
var self = require("sdk/self");
var data = self.data;
pageMod.PageMod({
include: "*.linustechtips.com",
contentScriptFile: [data.url("linustechtips-injection.js")],
contentScriptWhen:"ready",
onAttach: function(worker){
notificationQueue.push({title:"attached",text:"attached to ltt",});
worker.port.emit("dataUrl",data.url());
},
});
and the content script contains:
var dataUrl="";
self.port.on("dataUrl",function(data){dataUrl=data;setTimeout(function(){console.log(dataUrl);},5000)});
console.log("injected");
var $jq = jQuery.noConflict(); //jquery was conflicting and causing issues
Followed by some more code, but it runs, and if it is put insde the self.port.on(...) code, it never runs (the self.port.on(..) is never called because the onAttach is never called.
But while the script is injected as it should (in fact, it appears to run twice for some reason), the onAttach code is never called (it should display a desktop notification and emit the data.url().)
There are no errors logged to the firefox console.
The url of the site I'm using to test is http://linustechtips.com
Can provide a more complete example, including the content script? This code will fail as-is (you don't require the data utility object from the self module anywhere) and it is in the content script that you would need to listen for events sent via worker.port.emit, using self.port.on in the content script. For more on this:
https://developer.mozilla.org/en-US/Add-ons/SDK/Guides/Content_Scripts

Categories