I have a Firefox addon made with the add-on SDK.
https://addons.mozilla.org/es/firefox/addon/board-notes/
To add a toolbar button I use a popular library for the SDK toolbarbutton.js:
https://github.com/erikvold/toolbarbutton-jplib/blob/master/lib/toolbarbutton.js
I only want to add the icon when it first installs and it works, the icon appears but after restarting the browser the icon disappears. The user has to use the right click button to open the setup browser bar and drag the icon again to the bar. Then if he restarts the icon continue correctly in its place.
I want to fix this behaviour because the most part of users probably don't know that they can recover the icon with the setup options.
I've tested some functions to detect if the icon is not in his place to move again, but by doing this if the user hides the icon, when he restarts it will appear again. And this is forbidden by Firefox policies.
I'll appreciate any help, I'm going crazy.
The code I use is this:
button = createButton(options);
if (options.loadReason == "install")
{
button.moveTo({
toolbarID: "nav-bar",
insertbefore: "home-button"
});
}
function createButton(options) {
return toolbarbutton.ToolbarButton({
id: "NoteBoard",
label: "Note Board",
tooltiptext: "Note Board",
image: data.url("noteboardMini.png"),
onCommand: function() {
openPopup();
},
onContext: (function () {
var installed = false;
return function (e, menupopup, _menuitem) {
//Install command event listener
if (!installed) {
menupopup.addEventListener("command", function (e) {
var link = e.originalTarget.value;
if (link) open(link.replace(/\?.*/ , ""));
});
installed = true;
}
var temp = (function (arr) {
arr.forEach(function (item, index) {
for (var i = index + 1; i < arr.length; i++) {
if (arr[i] && item.label == arr[i].label) {delete arr[index]}
}
});
return arr.filter(function (item){return item});
})(loggedins);
//remove old items
while (menupopup.firstChild) {
menupopup.removeChild(menupopup.firstChild)
}
function addChild (label, value) {
var item = _menuitem.cloneNode(true);
item.setAttribute("label", label);
item.setAttribute("value", value);
menupopup.appendChild(item);
}
if (temp.length) {
temp.forEach(function (obj) {
addChild(obj.label, obj.link);
});
}
else {
addChild(_("context"), "");
}
}
})()
});
}
You could use the library Toolbar Button Complete, which is my fork of toolbarbutton.js.
Using the library
You can use this library the same way as the original toolbarbutton.js, but it also has more options and features.
In your main.js file:
button = createButton(options);
// On install moves button into the toolbar
if (options.loadReason == "install") {
button.moveTo({
toolbarID: "nav-bar",
insertbefore: "home-button",
forceMove: true
});
};
You can find a working example of the library here, but it is a bit out of date.
Installing the Library
If you are using the add-on SDK on your computer:
Download Toolbar Button Complete from github.com.
add it to your packages directory. (Either under your SDK directory or under your add-on's directory.)
If you are using the Add-on Builder to create your add-on:
Click the plus button next to your library folder:
Type in Toolbar Button Complete.
Click on the Add Library button:
Updating the Library
The library is hosted on github.com here.
If you are using the Add-on Builder for your add-on, you can simply click the little refresh button when there is an update available.
Related
I want to change the label of a widget when user click it, then I write the code looks like this:
var widgets = require("sdk/widget");
var statusBar = widgets.Widget({
id: "patchouliStatus",
label: "Wait Page Loading...",
contentURL: "http://www.mozilla.org/favicon.ico",
onClick: function(){
this.contentURL = "http://www.google.com/favicon.ico";
this.label = "Clicked";
}
});
When I click the widget, the icon has changed, but nothing happen to the label.I move the mouse to the widget and it still show "Wait Page Loading...".Is there a way to dynamically change the label?
Firefox: v27.0.1
Add-on SDK: v1.15
Widget's label is read-only. You must use tooltip attribute to show the user a text on mouse hover, this way:
var widgets = require("sdk/widget");
var statusBar = widgets.Widget({
id: "patchouliStatus",
label: "Wait Page Loading...",
contentURL: "http://www.mozilla.org/favicon.ico",
onClick: function(){
this.contentURL = "http://www.google.com/favicon.ico";
this.tooltip = "Clicked";
}
});
As docs says somewhere in this section -I think it could be more clearly documented-, tooltip value is an "optional text to show when the user's mouse hovers over the widget. If not given, the label is used". Also, examples in that section don't make it clear enough as I think they should.
Ok man thanks for the XPI, change changeLabel function to this, my above was really bugged.
function changeLabel(str){
var DOMWindows = Services.wm.getEnumerator('navigator:browser');
while (DOMWindows.hasMoreElements()) {
var aDOMWindow = DOMWindows.getNext();
var myWidget = aDOMWindow.document.getElementById('widget:jid1-njALX8gXKY872g#jetpack-patchouliStatus');
if (myWidget) {
Services.appShell.hiddenDOMWindow.console.info('myWidget:', myWidget);
myWidget.setAttribute('label', str);
myWidget.setAttribute('tooltiptext', 'tooltip changed');
} else {
Services.appShell.hiddenDOMWindow.console.info('myWidget null:', myWidget);
}
}
}
It also seems that the id of your widget starts with tyour addon id name.
Now I gave you the enumerator function because that goes over all windows and you can add event listener. But really if you just want to target the one that was clicked just get the most recent window, as that will obviously hold the correct window with your widget as we just clicked there and the event listener fires on click.
Change changeLabel to this:
function changeLabel(str){
var aDOMWindow = Services.wm.getMostRecentWindow('navigator:browser');
var myWidget = aDOMWindow.document.getElementById('widget:jid1-njALX8gXKY872g#jetpack-patchouliStatus');
if (myWidget) {
Services.appShell.hiddenDOMWindow.console.info('myWidget:', myWidget);
myWidget.setAttribute('label', str);
myWidget.setAttribute('tooltiptext', 'tooltip changed');
} else {
Services.appShell.hiddenDOMWindow.console.info('myWidget null:', myWidget);
}
}
Also that Services.appShell.hiddenDOMWindow.console.info is just something nice to debug, I left it in there so you can see how it works. It logs to "Browser Console" (Ctrl+Shift+J).
As a final note I used a non-sdk solution by requiring chrome. they advise you not to do that because they want you to use the SDK functions I don't know about SDK but you can use the getEnumerator and recentWindow function by requiring window/utils it looks like:
Read window/utils article here
I'll give you non-sdk solution here but someone will have to help convert it to sdk solution. You can paste this in your code it will work though.
Im not sure how the element is inserted into the dom but I guessed.
var {Cu, Ci} = require('chrome'); //if you want to paste this into scratchpad with with Environemnt set to Browser than dont need this line, this line is for sdk
var DOMWindows = Services.wm.getWindowEnumerator(null);
while (DOMWindows.hasMoreElements()) {
var aDOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
var myWidget = aDOMWindow.querySelector('#patchouliStatus'); //im not exactly sure how the element is inserted in the dom but im guessing here
if (myWidget) {
myWidget.label = 'rawr';
}
}
I have made a plugin using the addon SDK. The plugin adds a button to the nav-bar, and when it is clicked it opens a new tab with some data from an internal indexeddb using code similar to this:
// main.js
tabs.open({
url: self.data.url('index.html'),
onReady: runScript
});
function runScript(tab) {
var worker = tab.attach({
contentScriptFile: [
self.data.url("script.js")]
});
}
Everything works fine, except for the scenario where the user quits Firefox and opens it again, that tab will be restored, but it will contain nothing because it hasn't been triggered by the addon button click. This is because the scripts on the page are loaded through the runScript function in main.js, which is not executed when the HTML file is loaded on a restart.
How can I get this tab to have the same behavior on page startup than on button clicking?
I think you'll have to reload the tab:
exports.main = function(options) {
if(options.reason==='startup') for (var i=tabs.length-1; i>=0; i--) {
var tab = tabs[i];
if (tab.url!==self.data.url('index.html')) continue;
tab.once('ready', runScript.bind(null, tab));
tab.reload();
/* If it can't reload the tab,
use tab.url = self.data.url('index.html'); */
}
// ...
}
This a bug I had reported it awhile ago on bugzilla here
I added your topic as an example.
So what you have to do for now, is onReady, you have to turn you body into html datauri and set the location of the tab to this contents.
For example on ready:
var htmlDataUri = 'data:text/html,' + encodeURIComponent(document.documentElement.innerHTML);
//end make htmldatauri
document.location = htmlDataUri;
I used below code to add toolbar buttons automatically in navigation toolbar below Firefox Australis.
var buttonId = "toolbarbutton-toolbarbutton";
var navBar = document.getElementById("nav-bar");
var currentSet = navBar.currentSet;
var curSet = currentSet.split(",");
if (curSet.indexOf(buttonId) == -1)
{
navBar.insertItem(buttonId);
navBar.setAttribute("currentset", navBar.currentSet);
document.persist("nav-bar", "currentset");
try
{
top.BrowserToolboxCustomizeDone(true);
}
catch (e)
{
}
}
Because user interface and modules changed for Australis, the code needs to be updated. How can I add Toolbar Button for Australis proper way?
You have to use the CustomizableUI module:
try
{
Components.utils.import("resource:///modules/CustomizableUI.jsm");
CustomizableUI.createWidget({
id: "toolbarbutton-toolbarbutton",
defaultArea: "nav-bar",
removable: true,
label: "My button",
tooltiptext: "My tooltip text",
onClick: function()
{
alert("Clicked");
}
});
}
catch (e)
{
Components.utils.reportError(e);
// No such module? Try the old approach.
...
}
Note that the widget no longer needs to be added for each browser window, it is enough to do it once. Unfortunately, the module documentation is practically non-existent right now, the code above has been deduced from module's source code. The documentation should improve soon however.
If it helps, Adblock Plus source code contains an emulation of the CustomizableUI API for older Firefox versions. This one is far from complete however, it is only meant to cover the needs of Adblock Plus.
I have done a firefox addon using the Addon Builder. This addon display a panel containing a web page.
The problem I have is that I would like to keep this panel displayed and probably had a close button to hide it. Actually the panel disappear when we click out of the panel.
This is the code I use to make my panel:
var HauteurPopup = 400;
var LargeurPopup = 650;
function getPanel(contentURL){
var popupPanel = require("panel").Panel({
width:LargeurPopup,
height:HauteurPopup,
contentURL: contentURL
});
return popupPanel;
}
var btn = require("toolbarbutton").ToolbarButton({
id: 'propelink-button',
label: 'Propulesez ce lien!',
image: 'https://www.users.prplk.com/img/mini-logo-propel-bar.jpg',
onCommand: function() {
if (typeof(tabs.activeTab._worker) == 'undefined') {
let worker = tabs.activeTab.attach({
contentScript: btnContentScript
});
tabs.activeTab._worker = worker;
}
tabs.activeTab._worker.port.emit("btnContentScript");
var panelPopup = myPanel.getPanel("http://example.com");
panelPopup.show();
}
});
Someone know how to keep this panel displayed and close it adding a button?
Thanks in advance
In xul based extensions there is an option in the creation of the panel to accomplish that (panel.noautohide). In firefox-addon-sdk it seems that it doesn't exist. See 595040 – Add a "isPersistent" attribute for panels
Although it is mentioned that you can do a workaround by editing panel.js, but i never tried to do that, but you may want to give it a try.
I'm building a simple dialog plugin to replace the default link tool. The design calls for a particular layout that is difficult to achieve with the CKEdit dialog definition: We want a single field to appear above the tab elements in the dialog (see illustration).
Can anyone suggest a way that this might be implemented? Thanks!
As far as I can tell it is not possible to achieve this using the built-in dialog definition.
I was able to get around this limitation by building my dialog plugin using the iframedialog plugin. This basically pops up a CKEditor dialog window and loads an external URL into it. You can do anything you want in that iframe, and then return the text to CKEditor when the user presses the OK button.
A simple example:
// plugins/iframelink/plugin.js
CKEDITOR.plugins.add('iframelink', {
requires: ['iframedialog'],
init: function(editor){
CKEDITOR.dialog.addIframe('iframelinkDialog',
// title
'Insert a Link',
// src
this.path + 'dialogs/link.html',
// minWidth
500,
// minHeight
250,
// onContentLoad
);
var cmd = editor.addCommand('iframelink', {exec: iframelinkOnclick});
editor.ui.addButton('iframelink', {
label: 'Insert a Link (Special Link Tool)',
command: 'iframelink',
icon: this.path + 'images/world_link.png'
});
}
});
function iframelinkOnclick(editor){
dialog = editor.openDialog('msiteslinkDialog');
};
// plugins/iframelink/dialogs/iframelink.js
$(function() {
if (typeof(window.parent.CKEDITOR) != 'undefined') {
CKEDITOR = window.parent.CKEDITOR;
var dialog = CKEDITOR.dialog.getCurrent();
var editor = dialog.getParentEditor();
// Get value of the selected text:
var selection = editor.getSelection().getSelectedText();
// Do something when the user presses the OK button:
var okListener = function(ev) {
link = yourFunctionToDoSomethingClever();
this._.editor.insertHtml(link);
dialog.removeListener("ok", okListener);
};
// Bind the OK button to your okListener method:
dialog.on("ok", okListener);
};
}
So you can make the dialog look any way you want: