Firefox WebExtension toolbar buttons to toggle sidebars
Asked Answered
A

2

7

Since the Firefox Australis interface, there are no more toolbar buttons to toggle the Bookmarks and History sidebars with one click. There is the "show sidebars" toolbar button, but it displays an animated popup and requires 2 clicks.

So I'm trying to create a WebExtension to implement these buttons back.

  • a given WebExtension can add only one toolbar button, so I would have to create two separate extensions. This starts well... but ok, I'll deal with it.
  • sidebar_action doesn't add a toolbar button, so it rules out this method.
  • this leaves me with browser_action.

I tried many things, without success, for example:

  • Calling SidebarUI.toggle("viewBookmarksSidebar"); in a background.js script, but there is not defined SidebarUI object.
  • There is the chrome://browser/content/bookmarks/bookmarksPanel.xul URL, but I lack the sidebar to load it into.
  • I tried to combine sidebar_action and browser_action but that is not possible.
Averment answered 24/6, 2017 at 22:21 Comment(1)
Interestingly the commands AND the context menu already support _execute_sidebar_action. Unfortunately both shortcuts and right-click menus are very difficult to discover and really not the best way to present a sidebar-addon.Hoick
O
7

Opening your own sidebar with a browserAction button

You can have a browserAction toolbar button which opens your own sidebar. You can do this by defining both a sidebar_action and a browser_action in your manifest.json.

When this question was asked, it wasn't possible to combine both a sidebar_action and a browser_action in a manifest.json. I'm not sure when that actually changed, but as of this point (tested on FF71), you can have both.

The following is example code which will do this:

manifest.json:

{
    "manifest_version": 2,
    "name": "Button opens sidebar",
    "description": "Open the sidebar with a toolbar button.",
    "version": "1.0",

    "browser_action": {
        "default_icon": "icon.png",
        "default_title": "Open Sidebar"
    },
    "background": {
        "scripts":[
            "background.js"
        ]
    },
    "sidebar_action": {
        "default_icon": "icon.png",
        "default_title": "Example Sidebar",
        "default_panel": "sidebar.html",
        "open_at_install": false
    }
}

background.js:

//The manifest.json entry must be a file in your extension, but you can change it to
//  an external site in your background.js:
browser.sidebarAction.setPanel({panel: 'https://example.org/'});
//Open the sidebar when the browserAction button is clicked.
browser.browserAction.onClicked.addListener(() => {
  browser.sidebarAction.open();
});

sidebar.html

<html>
  <body>
    <div>Example text</div>
  </body>
</html>

Toggling the sidebar open/closed

I tried implementing a naive implementation of the button actually toggling the sidebar:

background.js

browser.browserAction.onClicked.addListener(() => {
    browser.sidebarAction.isOpen({}).then((isOpen) =>  {
        if (isOpen) {
            browser.sidebarAction.close();
        } else {
            browser.sidebarAction.open();
        }
    });
});

Unfortunately, this fails with the error:

Error: sidebarAction.open may only be called from a user input handler

Use a second browserAction onClicked

You can take advantage of the fact that a sidebar that's showing HTML from within your extension is running in the background context, by just adding an additional browserAction.onClicked listener in the sidebar which closes the sidebar.

background.js

browser.browserAction.onClicked.addListener(() => {
    browser.sidebarAction.open();
});

sidebar.js

browser.browserAction.onClicked.addListener(() => {
    browser.sidebarAction.close();
});

sidebar.html

<html>
  <head>
    <script src="sidebar.js"></script>
  </head>
  <body>
    <div>Example text</div>
  </body>
</html>

Event listeners are executed in the order they are added, so the one added by the sidebar.js, which closes the sidebar, is run after the one in background.js, which opens the sidebar. Thus, when the sidebar is open, it gets closed upon the browserAction button being clicked.

Can't open the actual Bookmark or History sidebar

What you specifically desire, opening the actual Bookmarks or History sidebar, is not possible with WebExtensions. What you could do is implement similar sidebars yourself.

I did try changing the sidebar URL to a chrome:// URL:

browser.sidebarAction.setPanel({panel: 'chrome://browser/content/aboutDialog.xul'});

Unfortunately, that results in an error:

Error: Access denied for URL chrome://browser/content/aboutDialog.xul

If you desire some way to programmatically open the actual Bookmark or history sidebars, then you will need to file a bug requesting the functionality. Alternately, you can also create a WebExtension Experiment which adds the functionality to the WebExtensions API when the WebExtension Experiment is installed. WebExtension Experiments do not automatically get integrated into Firefox, but there is the possibility that it can be.

Outstrip answered 25/6, 2017 at 3:23 Comment(5)
Thanks, you confirmed what I was fearing. How dare they force people to move to such a limited system… Of course, bug filled.Averment
@GrasDouble, Yeah, my plan is to stay away from Firefox Release after v57 for as long as possible (using ESR and/or Developer Edition/Nightly, depending on what keeps me able to use the extensions I want to, including unpublished personal extensions). Once that's not possible, the only thing that will keep me on Firefox is the required human review of all extensions before listing. Other than that, they're changing it into a reduced functionality clone of Chrome (OK, some slight areas with more capability). Tossing out 100's of 1,000s of hours (if not more) of extension development.Outstrip
The functionality may have been implemented now, per bugzilla.mozilla.org/show_bug.cgi?id=1341126. I would have to give all of this programming a new try. Or search if suitable addons have been created already.Averment
@GrasDouble Thanks for the ping. I'll take a more detailed look at it and update this answer. A brief look at that bug makes me think it's unlikely they added the capability to do what you're actually asking about here: open the stock bookmarks or history sidebars. That bug appears to be more about having a programmatic way to open the extension's own popup/sidebar.Outstrip
You seem to be right. So, we still can't do better than the native "Show sidebars" toolbar button. Sigh. Meanwhile, I got used to the shortcuts Ctrl+B and Ctrl+H (easy to remember!). And personally, the definite solution will be Pale Moon once it has switched to UXP (much more compatible with websites, currently in beta).Averment
T
6

Firefox ⩾ 73

Since Firefox 73, you can simply use:

browser.browserAction.onClicked.addListener(() => {
    browser.sidebarAction.toggle();
});

Documentation on MDN

Firefox < 73

If you need to support older Firefox versions, especially ESR, you can keep track of what sidebar is open. This is the method I developed for one of my addons and the only one I know that works correctly with several windows.

In your background script:

let openedSidebarWindows = {};
browser.runtime.onConnect.addListener(port => onConnect(port));
browser.browserAction.onClicked.addListener(tab => this.onClick(tab));

function onConnect(port) {
  const windowId = parseInt(port.name);
  openedSidebarWindows[windowId] = port;
  port.onDisconnect.addListener(port => {
    delete openedSidebarWindows[parseInt(port.name)];
  });
}

function onClick({ windowId }) {
  if (openedSidebarWindows[windowId] !== undefined) {
    browser.sidebarAction.close();
  } else {
    browser.sidebarAction.open();
  }
}

In your sidebar script:

browser.runtime.connect({ name: windowId.toString() });
Thyroxine answered 22/3, 2020 at 23:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.