How to add a text label and connected buttons

I am still new to the Add-on development and using jpm.

For a new add-on I need a text label in the tabs toolbar and two connected buttons like the Bookmark Buttons.

I read a lot of tutorials and googled it, but didn’t find an answer.
Does anyone know how to do that?

First I wanted to use the SDK ui API, but it is very limited (ui API)
But then I found a similar question on stackoverflow.com about CustomizableUI.jsm and it seems quite good.

For now I only build a ‘custom button’, but I just want some text field (NOT a input field, just text like a timer or the number of open tabs).
Has somebody an idea what the code for a text field is?

const {Cu} = require("chrome");
Cu.import('resource:///modules/CustomizableUI.jsm');
CustomizableUI.createWidget({
    id: 'navigator-throbber', //id in cui.jsm // SHOULD match id of that in dom (Line #11)
    type: 'custom',
    defaultArea: CustomizableUI.AREA_TABSTRIP,
    onBuild: function(aDocument) {
        var toolbaritem = aDocument.createElementNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul', 'toolbaritem');
        var image = aDocument.createElementNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul', 'image');
        image.setAttribute('src', 'chrome://branding/content/icon16.png');

        var props = {        
            id: 'navigator-throbber', //id in dom // SHOULD match id of that in cui.jsm (Line #2)
            title: 'Activity Indicator',
            align: 'center',
            pack: 'center',
            mousethrough: 'always',
            removable: 'true',
            sdkstylewidget: 'true',
            overflows: false
        };

        for (var p in props) {
            toolbaritem.setAttribute(p, props[p]);
        }

        toolbaritem.appendChild(image);
        return toolbaritem;
    }
});

I don’t know too much about xul elements but a label works:

CustomizableUI.createWidget({
    id: "test_text_widget",
    defaultArea: CustomizableUI.AREA_TABSTRIP,
    type: "custom",
    onBuild: doc => {
      let label = doc.createElement("label");
      label.setAttribute("value", "ABC");
      
      let item = doc.createElement("toolbaritem");
      item.setAttribute("id", "test_text_widget9")
      item.appendChild(label);
      return item;
    }
  })

Add to the class of your button: badged-button and then add attribute badge and set it to a value and you can get a label like this:

You can then add a stylesheet to colorize the label, so like:

#cui_nativeshot .toolbarbutton-badge {
    background-color: #00A8EC;
}

To get the double button style toolbarbutton you have to set the attribute of type to menu-button. They didnt design badged-button to be used with menu-button type so you’ll have to mess with the CSS to get it to look the way you like.

Many thank for all the help. I appreciate that.

@MartijnJ It works and looks great. But I must admit I have no idea whats after onBuild happens.
Is there a tutorial or a reference on how to use CustomizableUI.jsm (like a list of methods and attributes)?
And most important, how can I change the “value” Attribut? How can I access the label from a different function?

@noitidart I think you got me wrong. Or I misunderstood you.
I wanted two different things: a text field next to the tabs and independently two buttons that looked like the bookmark buttons.
For the text label I don’t want to use a Badged button because I don’t need a button, just text.
And the CustomizableUI.jsm seems suitable and has the advantage that i can define the toolbar and the position.

Do you mean toolbar button (XUL)?
Is therr a different way without XUL in order to be restartless.
I just don not want the two buttons to get seperate.

What happens in Firefox after the onBuild function? Or is it the code I posted you are referring to?

You posted a link to the documentation yourself, haha.
https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/CustomizableUI.jsm
All the methods and attributes should be there.
And here are the options for the widget configuration:
https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/CustomizableUI.jsm/API-provided_widgets

I’m not sure I get the problem. Like this?

let label;

function aDifferent(){
  label.setAttribute("value", "XYZ");
}

CustomizableUI.createWidget({
    ---------------
    onBuild: doc => {
      label = doc.createElement("label");
    ---------------
  }
});
1 Like

FWIW, although I don’t have a more concrete suggestion as I don’t fully understand the question either, I’m almost sure the code you posted wouldn’t work. The onBuild is called on every new browser window, so it would replace |label| all the time with a new instance, and it would be hard to predict which document/instance it refers to that way.

If the label is specific to each button, it might be better to add each label node to a set or an array instead of assigning it to a variable directly, or use CustomizableUI.getWidget(…).forWindow(…) when you need to get a specific one; I guess it would depend on why/how you need to use it.

If the label is created independently from the buttons (which I believe is the goal here), then you can just… use it?.. This is the part I’m not sure I follow. :confused:

The bookmarks double button is just a menu-button , with some special CSS styling to make its dropdown arrow look like another full button. As noitidart mentioned, you’ll have to style it like that yourself, as there’s no native helper/creator for it.

Or you can just create a toolbaritem and stick two toolbarbuttons in it. :smile:

Oh I see, you might find this topic useful:

You are right. I build two different add-ons. For the first I need a text label/field next to the tabs bar and for the second add-on I need two regular buttons (which cant be seperate). Sorry if I expressed myself wrong. I am a addon and javascript noob. I just followed the Add-on SDK Tutorials and didn’t find what I was looking for.

Add-on 1: Text

The Code you posted. It just took me some time to understand the difference between .createElementNS() and .createElement()
But I still don’t understand onBuild: doc => {. I haven’t seen it before. Always onBuild: function(aDocument) {

I want the text to show me the number of open tabs of the window. So if I have more windows open with a different number of tabs the text is different in each window (and should change if a tab is opened or closed). I know how to count the tabs and I added the listener for open/close tabs and windows to update the number. If a tab is opened or closed the listener calls a fuction to update the number. At the moment I only use console.log().

Add-on 2: Button
And I think my approach was wrong and I settled to early on the Bookmark button. Instead I just want two buttons next to each other, that can’t be seperate.

And how can i stick them together? CustomizableUI.jsm?

Something like as in MartijnJ’s first response. Except instead of a label element, you create and append two toolbarbuttons to the toolbaritem. (Note that I’ve never actually tested this, but I don’t see a reason for why this wouldn’t work.)

Thanks, I’ll give it a try.
In addition to @noitidart link I found two similar topics on stackoverflow. That probably helps to get some practical knowledge on CustomizableUI.jsm

Ah, that’s just a fat arrow function.
It’s not important in this case, just shorter to write.

But I was looking for a complete list. It list id, type, label, removable, overflows but not title, align, pack, mousethrough or sdkstylewidget

Thats exactly what happened. Only the text of the newest opened windows is change.
Like you said, I probaly need different variables for each window (set or array) to change the text of all windows. (And always know which “text variable” belongs to the right window)