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
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();
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;
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.
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.
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
});
}
});