How to create a button near the address bar? - firefox

I am designing a firefox extension, and I want to add a button near the address bar. And then I need to attach a bookmarklet to that button.
Someone can tell me what APIs do I have to use to create that button and to add the bookmarklet ?

Here's an example that uses Erik Vold's toolbarbutton library to add a button near the addressbar:
const data = require("self").data;
const tabs = require("tabs");
exports.main = function(options) {
var btn = require("toolbarbutton").ToolbarButton({
id: 'my-toolbar-button',
label: 'Add skull!',
image: data.url('skull-16.png'),
onCommand: function() {
if (typeof(tabs.activeTab._worker) == 'undefined') {
let worker = tabs.activeTab.attach({
contentScript: 'self.port.on("sayhello", function() { alert("Hello world!"); })'
});
tabs.activeTab._worker = worker;
}
tabs.activeTab._worker.port.emit("sayhello");
}
});
if (options.loadReason === "install") {
btn.moveTo({
toolbarID: "nav-bar",
forceMove: false // only move from palette
});
}
};
You can also see this as a runnable example on the Add-on Builder site:
https://builder.addons.mozilla.org/addon/1044724/latest/

Related

Using Electron window objects from window Manager

I'm trying to send messages to my main window like show and hide, but it keeps saying that my main window is undefined. I'm not sure why. When i try assigning the result of open on the window manager the api says that it returns the object, but that doesn't seem to work how i understand it. Could you guys help me?
const electron = require('electron')
const Menu = require('electron').Menu
var path = require('electron').path
var windowManager = require('electron-window-manager');
const app = electron.app
const BrowserWindow = electron.BrowserWindow
var Tray = require('electron').Tray
var nativeImage = require('electron').nativeImage
var tray = null
var myValue;
var mainWindow;
const notifier = require('node-notifier');
var notified = 0;
// Modify the user agent for all requests to the following urls.
const filter = {
urls: ['https://*.github.com/*', '*://electron.github.io']
}
app.on('ready', function(){
var icon1 = nativeImage.createFromPath(`${__dirname}/../build/timer.png`)
tray = new Tray(icon1)
tray.setToolTip('Timer')
var icon2 = nativeImage.createFromPath(`${__dirname}/../build/timer.png`)
var contextMenu = Menu.buildFromTemplate([
{ label: 'Open Window', click: function(){
windowManager.get('home').show();
} },
{ label: 'Exit', click: function(){
app.isQuiting = true;
app.quit();
}
}
]);
tray.setContextMenu(contextMenu)
tray.setImage(icon1)
tray.on('click', () => {
windowManager.open('home', 'welcome', `file://${__dirname}/index.html`)
})
windowManager.init({
'onclose': function(event){
event.preventDefault()
}
});
// Open a window
windowManager.open('home', 'welcome', `file://${__dirname}/index.html`);
//mainWindow.loadURL(`file://${__dirname}/index.html`)
notifier.on('click', function(notifierObject, options) {
windowManager.get("home").show();
notified = 0;
})
notifier.on('timeout', function (notifierObject, options) {
// Triggers if `wait: true` and notification closes
mainWindow.show();
notified = 0;
});
/*
mainWindow.on('minimize',function(event){
event.preventDefault()
mainWindow.hide();
});
mainWindow.on('close', function (event) {
if( !app.isQuiting){
event.preventDefault()
mainWindow.hide();
}
return false;
});
*/
})
I found the solution. windowManager.createNew(....) only gives you a window object, in order to get a browser window, which allows you to show, hide, and add listeners, you do something like this
mainWindow = windowManager.createNew('home', 'welcome', file://${__dirname}/index.html);
mainWindow.create();
mainWindow.object.show();

How to get the title of all the tabs which is open in multiple window in firefox?

I'm creating a firefox extension using Add-on SDK, which will display all the tab details including memory, title and url. I have tried to get the tab title using require("sdk/tabs"); tab package.
Below is the sample code:
popup.js
<body>
<ul>
<li>
Settings
</li>
</ul>
<script type="text/javascript" src="popup.js"></script>
</body>
popup.js
var tab_button = document.getElementById("tab_list");
tab_button.addEventListener("click", function() {
addon.port.emit("GET_TABS");
});
main file: index.js
const buttons = require("sdk/ui/button/action");
const { TogglePanel } = require("popupPanel");
var button = buttons.ActionButton({
id: "mem-tools",
label: "tabs info listing",
icon: {
"16": "./tab.png",
},
onClick: handleClick
});
let togglePanel = new TogglePanel();
function handleClick(state) {
togglePanel.panel.show({position:button});
}
Panel file: popupPanel.js
var Panel = require('sdk/panel');
var self = require('sdk/self');
var { MemoryHandler } = require('memory-handler');
var memoryHandler = new MemoryHandler();
function TogglePanel() {
this.panel = new Panel.Panel({
width: 150,
height: 200,
contentURL: self.data.url("popup.html")
});
this.panel.port.on("GET_TABS", function() {
memoryHandler.getAllTabs();
});
}
exports.TogglePanel = TogglePanel;
memory-handler.js
var tabs = require('sdk/tabs');
function MemoryHandler() {
return {
getAllTabs: () => {
for(let tab of tabs) {
console.log(tab.title);
}
}
}
}
exports.MemoryHandler = MemoryHandler;
This code only fetching all tab titles from the main window and child window, but not from all other new window's tabs which is opening using _blank attribute.
Note: we can easily recreate the issue just create an html page and use the below code:
Visit me
The page open using the "_blank" attribute is not coming under the tabs array.
Any help is appreciated.
Thanks in advance!!
We can get all the titles from all the window tabs by creating a custom array.
index.js
var memoryHandler = new MemoryHandler();
tabs.on('ready', function(tab) {
memoryHandler.addTabDetails({id: tab.id ,title: tab.title, url: tab.url});
});
If you want to get the title which is setting by using javascript after page load, you can inject a mutation observer code in the content script of tab
memory-handler.js
var presentTabs = []
function MemoryHandler() {
return {
addTabDetails: (tab_array) => {
presentTabs.push(tab_array);
}
}
}
exports.MemoryHandler = MemoryHandler;

Firefox Addon - UI Creation

I wanted to create a firefox add-on, which will display a form to user.
I am started with SDK isntallaion and documentation. I am able to create a toggle button which will open a panel to user.
var { ToggleButton } = require('sdk/ui/button/toggle');
var panels = require('sdk/panel');
var self = require('sdk/self');
var button = ToggleButton({
id: 'btn-sc',
label: 'Test Addon',
icon: {
"16": "./icon-16.png",
"32": "./icon-32.png",
"64": "./icon-64.png"
},
onChange: handleChange
});
var panel = panels.Panel({
contentURL : self.data.url("./panel.html"),
onHide : handleHide
});
function handleChange(state){
if(state.checked){
panel.show({
position: button
});
}
}
function handleHide(){
button.state('window', {checked:false});
}
How do I add more buttons and textbox to this panel?
Create them with HTML in panel.html. If you don't have a panel.html file yet, place it in the data folder. Style with CSS, listen for clicks with JS. It's just a normal webpage.

Firefox Addon - Accessing pre-loaded content script from ActionButton

I am attaching content script to every tab on my firefox add-on.
And if user clicks on ActionButton (top right icon on browser) I am trying to access content script handler function, but it does not work.
I am using walkthroughs from Content Scripts but still could not make it work.
Am I doing something wrong?
Please see code below the TODO marked areas are not working;
// main.js
tabs.on('ready', function (tab) {
var worker = tab.attach({
include: "*",
//contentScript: 'window.alert("Page matches ruleset");',
contentStyleFile: [data.url("scripts/myTestContent1.js")]
});
worker.port.on('listener1', function (params) {
// I will listen some messages coming from myTestContent1.js
});
console.log("main.js: tab is ready!");
});
// browser icon typically at top right
var button = buttons.ActionButton({
id: "myActionButton",
label: "My pretty add-on",
icon: {
"16": "./icon-16.png",
"32": "./icon-32.png",
"64": "./icon-64.png"
},
onClick: handleClick
});
// when top right browser icon button is clicked
function handleClick(state) {
var myWorker = tabs.activeTab.attach({
//contentScriptFile: // I do not want to attach anything, just get Active tab!
});
// TODO this code is not handled by active tab's content script
// should be handled by myTestContent1.js but does not work
myWorker.port.emit("initialize", "Message from the add-on");
}
myWorker.port.emit is not calling handler function on my content script.
// myTestContent1.js
// TODO this code is not calling :(
self.port.on("initialize", function () {
alert('self.port.on("initialize")');
});
I fixed the problem by keep tracking tab-worker pairs, so
var TabWorkerPair = function (tabid, worker) {
this.tabid = tabid;
this.worker = worker;
};
tabs.on('close', function (tab) {
for (var i = 0; i < TabWorkerPairList.length; i++) {
var pair = TabWorkerPairList[i];
if (pair.tabid == tab.id) {
// remove object from list
TabWorkerPairList.splice(i, 1);
break;
}
}
console.log("main.js > tabs.on('close') > TabWorkerPairList count: " + TabWorkerPairList.length);
});
tabs.on('ready', function (tab) {
var worker = tab.attach({
include: "*",
contentScriptFile: [data.url("scripts/myTestContent1.js")]
});
// queue workers for tab
var pair = new TabWorkerPair(tab.id, worker);
TabWorkerPairList.push(pair);
console.log("main.js: tab is ready!");
});
and finally I can now emit worker function;
// when top right browser icon button is clicked
function handleClick(state) {
for (var i = 0; i < TabWorkerPairList.length; i++) {
var pair = TabWorkerPairList[i];
if (pair.tabid == tabs.activeTab.id) {
pair.worker.port.emit("initialize", pair.tabid);
break;
}
}
}
main reason: a tab can have multiple workers. So you should manually access the worker you are interested in.

Firefox Add-on How to Link context menu and panel widget

I want open/show my panel widget by click on my context-menu item to send some data from the dom position click to my panel.
I'm open for lot of solutions !
I don't know if this works but try it out, its sdk style
var panels = require("sdk/panel");
var self = require("sdk/self");
var panel = panels.Panel({
contentURL: self.data.url("panel.html")
});
var cm = require("sdk/context-menu");
cm.Item({
label: "Edit Image",
context: cm.SelectorContext("img"),
contentScript: 'self.on("click", function () {' +
' self.postMessage(null);' +
'});',
onMessage: function (msg) {
panel.show({
//position: button //set position to some anchor
});
}
});

Resources