I would like to save the HTML document in the current tab using a Firefox Add-on created with the Add-on SDK.
I'm trying like this:
exports.main = function() {
require("widget").Widget({
id: "foo",
label: "My Test",
contentURL: "http://www.mozilla.org/favicon.ico",
onClick: function(event) {
var {Cc, Ci} = require("chrome");
var persist = Cc["#mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
var localPath = Cc["#mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
localPath.initWithPath("/tmp/");
var localFile = localPath.clone();
localFile.append("mylocalfile.html");
var tabs = require("tabs");
persist.saveDocument(tabs.activeTab, localFile, localPath, null, 0, 0);
}
});
};
But the code above crashes Firefox (15.0) when I click on the widget.
I guess that tabs.activeTab might not be a nsIDOMDocument? Is that the problem?
How should I do to make it work?
tabs.activeTab is definitely not an nsIDOMDocument, please see the docs here:
https://addons.mozilla.org/en-US/developers/docs/sdk/latest/packages/addon-kit/tabs.html
You should instead be able to simply open a tab via tabs.open, and attach content scripts to the opened tab. Here is an example of how to attach content scripts to an opened tab:
https://builder.addons.mozilla.org/package/22176/latest/
Related
Trying to create a simple addon to retry a duckduckgo search in google. It parses the current duckduckgo url search params, appends them to a google url, and opens that url in a new tab.
The searchGoogle.js works great when pasted directly into the console context of a duckduckgo search. And the addon loads correctly in about:debugging... But I am unable to get the "searchGoogle.js" to fire on button (browser_action) click. What am I missing here?
manifest.json
{
"manifest_version": 2,
"name": "SearchGoogle",
"version": "1.0",
"description": "Repeats a duckduckgo search in a new tab using google.",
"icons": {
"48": "icons/48search-pointer-icon.png",
"32": "icons/32search-pointer-icon.png",
"16": "icons/16search-pointer-icon.png"
},
"permissions": [
"tabs",
"activeTab",
"webRequest",
"webNavigation"
],
"browser_action": {
"default_icon": "icons/48search-pointer-icon.png",
"default_title": "SearchGoogle"
},
"background": {
"scripts": ["searchGoogle.js"]
}
}
searchGoogle.js
var myStr = window.location.href;
var googurl = 'https://www.google.com/search?q=';
var params = getmyuri('q', myStr);
window.open(googurl+params, '_blank');
window.focus();
window.alert(googurl+params);
function getmyuri(n,s){
n = n.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");
var p = (new RegExp("[\\?&]"+n+"=([^&#]*)")).exec(s);
return (p===null) ? "" : p[1];
}
What you're currently doing is merely declaring a background script. A background script is loaded when the addon is loaded by the browser, but you need some code to react to other events.
Here's what I found in the MDN pages of browser_action :
If you don't supply a popup, then a click event is dispatched to your extension's background scripts when the user clicks the button.
(...)
The extension's background scripts can receive click events when the user clicks the icon using code like this:
browser.browserAction.onClicked.addListener(function(){})
So in your case, you need to wrap your "on click" code into this browserAction.onClicked event handler, something like this:
// searchGoogle.js
browser.browserAction.onClicked.addListener(function(){
var myStr = window.location.href;
var googurl = 'https://www.google.com/search?q=';
var params = getmyuri('q', myStr);
window.open(googurl+params, '_blank');
window.focus();
window.alert(googurl+params);
});
And voilĂ , your code should be executed everytime you click the browserAction icon.
For anyone else who comes here with the same question. Here are lessons observed:
window.alert is not a thing in a background script. Instead, wrap things in console.log(). Logging to console from Firefox extension?
Event listeners can pass tab information already, see tabs.getCurrent() result is undefined?.
To fire on button click, DON'T supply a popup in the manifest, and DO wrap the code to be fired in browser.browserAction.onClicked.addListener(function(){}).
Here's the final working script.
Main stays the same.
JS is:
browser.browserAction.onClicked.addListener(function(tab){
function getmyuri(n,s){
n = n.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");
var p = (new RegExp("[\\?&]"+n+"=([^&#]*)")).exec(s);
return (p===null) ? "" : p[1];
}
console.log(tab)
var googurl = 'https://www.google.com/search?q=';
var params = getmyuri('q', tab.url);
browser.tabs.create({url: googurl+params});
});
following the Tutorials i made an addon which is working with "jpm run" but not after installing the xpi file. I read the issue197 but thats for "icons". The AddOn is shown correctly both ways.
But the clickEvent only works with "jpm run".
Function of the AddOn:
clicking in the frame.html runs the javascript
function FrameClick(){
window.parent.postMessage("Frame is clicked","*");
}
The index.js should then open a Panel.
My code in index.js:
var data = require("sdk/self").data;
var mypanel = require("sdk/panel").Panel({
contentURL: data.url("panel.html"),
contentScriptFile: data.url("panel.js")
});
var { Frame } = require("sdk/ui/frame");
var frame = new Frame({
url: "./frame.html"}
);
var { Toolbar } = require("sdk/ui/toolbar");
var toolbar = Toolbar({
name: "toolbar",
title: "Toolbar",
items: [frame]
});
frame.on("message",MessageFromFrame)
function MessageFromFrame(e){
console.log("MessageFromFrame: "+e);
mypanel.show({position: {top:10,left:10}});
}
mypanel.on("show", function() {
mypanel.port.emit("show",ShowFromMyPanel);
});
function ShowFromMyPanel(e){
console.log("ShowFromMyPanel: "+e);
}
The data structure is:
myaddon
index.js
package.json
myaddon/data
frame.html
frame.js
panel.html
Any suggestions where to look for the error?
Thanks for reading :)
I'm trying desperately to create a Firefox add-on that posts a file with the field name "Filedata" to a particular PHP script which will only work if it sees a JPG in the $_FILE["Filedata"] variable.
I put a web form with a file browser into panel.html, then I take the image and turn it into a canvas which I turn into a blob and send to main.js. I would be happy to send the file directly from panel.js, but nothing at all happens (no error message either) when I attempt to so.
In main.js, I have this code but I get an error message that FormData doesn't exist in main.js. What to do?
function ajupload(mydata) {
var fd = new FormData();
fd.append("Filedata", mydata);
const {XMLHttpRequest} = require("sdk/net/xhr");
var myrequest = new XMLHttpRequest();
myrequest.open('POST', 'MYSITE/image.php?action=upload');myrequest.setRequestHeader("Content-type","application/x-www-form-urlencoded");
myrequest.upload.addEventListener("progress", function(e) {
var percentage = Math.round((e.loaded * 100) / e.total);
}, false);
myrequest.onreadystatechange=function()
{
if (myrequest.readyState==4 && myrequest.status==200)
{
console.log("Response" + myrequest.responseText);
}
}
myrequest.send(fd);
}
I recently started learning firefox addon development using Addon-SDK.
I created a simple addon which displays the current webpages URL, but I'm not getting the results.
Here's my main.js file
var widgets = require("sdk/widget");
var tabs = require("sdk/tabs");
var data = require("sdk/self").data;
var showipWidget = widgets.Widget({
id : "show-ip",
label : "Display IP Address of current Page",
contentURL : data.url("lens_icon.png"),
contentScriptURL : data.url("click_handler.js"),
/*onClick : function() {
var curtab = tabs.activeTab;
console.log(curtab.url+" is Opened in Browser.");
}*/
});
And The ContentScript click_handler.js
document.write(document.URL);
However when I use onClick event (commented code above) the URL is logged in console.
I think I'm accessing document object in wrong way. Can anyone show me how to do it right way.
That's weird that should work.
But try putting this in your content script:
var check = self.port.on("check", function() {
var location = window.location.href;
alert(location + " is opened in browser");
}
then emit that check function.
Figured out my problem. It was a silly mistake, I used contentScriptURL which is wrong. The correct term is contentScriptFile. I mixed content and contentURL with contentScript.
Reference from firefox:
http://tinypic.com/r/34447mc/8
I am trying to create a FF AddOn that brings some XML data from a website. But I can't find a way to parse my RESPONSE. First I used DOMParser but I get this error:
ReferenceError: DOMParser is not defined.
Someone suggested to use XMLHttpRequest, because the parsing is done automatically but then I get this other error:
Error: An exception occurred. Traceback (most recent call last):
File
"resource://jid0-a23vmnhgidl8wlymvolsst4ca98-at-jetpack/api-utils/lib/cuddlefish.js",
line 208, in require
let module, manifest = this.manifest[base], requirer = this.modules[base]; TypeError: this.manifest is undefined
I really don't know what else to do. I must note that I am using the AddOn Builder to achieve this.
Below the code that doesn't seem to work.
Option 1:
exports.main = function() {
require("widget").Widget({
id: "widgetID1",
label: "My Mozilla Widget",
contentURL: "http://www.mozilla.org/favicon.ico",
onClick: function(event) {
var Request = require("request").Request;
var goblecontent = Request({
url: "http://www.myexperiment.org/search.xml?query=goble",
onComplete: function (response) {
var parser = new DOMParser();
var xml = parser.parseFromString(response.text, "application/xml");
var packs = xml.getElementsByTagName("packs");
console.log(packs);
}
});
goblecontent.get();
}
});
};
Option 2:
exports.main = function() {
require("widget").Widget({
id: "widgetID1",
label: "My Mozilla Widget",
contentURL: "http://www.mozilla.org/favicon.ico",
onClick: function(event) {
var request = new require("xhr").XMLHttpRequest();
request.open("GET", "http://www.myexperiment.org/search.xml?query=goble", false);
request.send(null);
if (request.status === 200) {
console.log(request.responseText);
}
}
});
};
DOMParser constructor isn't defined in the context of SDK modules. You can still get it using chrome authority however:
var {Cc, Ci} = require("chrome");
var parser = Cc["#mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
nsIDOMParser documentation.
That said, your approach with XMLHttpRequest should work as well. You used the new operator incorrectly however, the way you wrote it a new "require object" is being created. This way it should work however:
var {XMLHttpRequest} = require("xhr");
var request = new XMLHttpRequest();
Please consider using an asynchronous XMLHttpRequest object however, use request.onreadystatechange to attach your listener (the xhr module currently doesn't support other types of listeners or addEventListener).
If you use XMLHttpRequest (available via the xhr module) you can easily avoid the use of DOMParser. Bellow I provide an example supposing request is an XMLHttpRequest object which request is successfully completed:
Instead of:
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(request.responseText, "application/xml");
Use:
var xmlDoc = request.responseXML;
An then you can:
var packs = xmlDoc.getElementsByTagName("packs");
console.log(packs);
Or whatever.