Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Firefox addon panel determine when it is shown and hidden?

I am using the Tool API to add a panel to Firefox DevTools.
I can define setup() and dispose() methods to handle initialization and teardown.

However I can’t figure out how to determine whether the panel is currently visible, or when it changes visibility. Is this event exposed somewhere?

To be clear, I only want to know that for my panel. So I want to know when my panel becomes visible, or when the user switches away to e.g. the Elements tab.

like image 572
Dan Abramov Avatar asked Aug 26 '16 18:08

Dan Abramov


1 Answers

The dev/panel API does not expose a method for you to be notified when the visibility of your panel changes. However, you can go around the API and be informed that the visibility has changed.

The code below calls the function panelVisibilityChangedState when the visibility changes of the panel created by the extension within the Developer Tools Toolbox. As requested, this is only the state of the panel added by the extension. This add-on was tested while running multiprocess Firefox Developer Edition, version 50.0a2.

This code is based on the MDN repl-panel example available on GitHub.

main.js:

//This code is based on the MDN Dev Tools panel example available at:
//    https://github.com/mdn/repl-panel

//Require the needed SDK modules
const { Panel } = require("dev/panel");
const { Tool } = require("dev/toolbox");
const { Class } = require("sdk/core/heritage");
const self = require("sdk/self");
var myRadio;
var devToolsToolbar;
var devToolsToolboxTabs;
var pickerContainer;
var panelIsVisible=false;

function panelVisibilityChangedState(isVisible){
    //This function may be called slightly before the state change actually occurs.
    panelIsVisible=isVisible;
    console.log('Dev Tools Panel Changed State: visibility is now: ' + isVisible );
}

function devToolsClickHandler(event){
    //The event fires before the value of the 'selected' attribute changes in response to
    //  this click, except when the event fires on the pick element. In that case, the
    //  'selected' attribute  is accurately 'false'.
    let isSelected = myRadio.getAttribute('selected') === 'true';
    let pickElementContains = pickerContainer.contains(event.target);
    if(!devToolsToolboxTabs.contains(event.target) && !pickElementContains){
        //Of the controls not in the devToolsToolboxTabs, only the pickElement changes
        //  the state of this panel being shown. The exception to this is the close
        //  button, but closing is detected via the panel's dispose method.
        return;
    }//else
    let doesContain = myRadio.contains(event.target);
    if((pickElementContains && panelIsVisible)
        || (doesContain && !isSelected) || (!doesContain && isSelected)) {
        panelVisibilityChangedState(doesContain);
    }
}

//Define a REPLPanel class that inherits from dev/panel
const REPLPanel = Class({
  extends: Panel,
  label: "Visi",
  tooltip: "Demo Dev Tool Panel Visibility Notification",
  icon: self.data.url("noIcon.png"),
  url: self.data.url("blank-panel.html"),
  setup: function(options) {
    //Remember the button which was clicked to open this panel (actually a <radio>)
    myRadio = require("sdk/window/utils").getFocusedElement()
    //For convenience and to speed up the event handler, remember three elements.
    //  Obtain these elements using IDs, or unique class when no ID is available.
    //  This should be a bit more stable than using the location in the DOM
    //  relative to myRadio.
    devToolsToolbar = myRadio.ownerDocument.querySelector('.devtools-tabbar');
    //An alternate method of finding the Dev Tools toolbar:
    //devToolsToolbar = myRadio.ownerDocument.getElementById('toolbox-tabs').parentNode;
    //Another alternate method of finding the Dev Tools toolbar:
    //devToolsToolbar = myRadio.parentNode.parentNode;
    devToolsToolboxTabs = devToolsToolbar.querySelector('#toolbox-tabs');
    pickerContainer = devToolsToolbar.querySelector('#toolbox-picker-container');
    devToolsToolbar.addEventListener('click',devToolsClickHandler,false);
  },
  dispose: function() {
    //Dev Tools panel is destroyed. Visibility is, obviously, false
    if(panelIsVisible){
        panelVisibilityChangedState(false);
    }
  },
  onReady: function() {
    //The panel is now visible and ready.  If desired, this call to
    //  panelVisibilityChangedState could be placed in the 'setup' function.
    panelVisibilityChangedState(true);
  }
});
exports.REPLPanel = REPLPanel;

//Create a new tool, initialized with the REPLPanel's constructor
const replTool = new Tool({
  panels: { repl: REPLPanel }
});

data/blank-panel.html:

<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    This is a blank panel
  </body>
</html>

package.json:

{
  "name": "dev-panel-visibility-notification",
  "title": "dev-panel-visibility-notification",
  "id": "dev-panel-visibility-notification@example",
  "description": "Demonstrates calling a function when the visibillity of the add-on's Dev Tools panel changes.",
  "author": "Makyen",
  "license": "MPL 2.0",
  "version": "0.1.0",
  "main": "main.js"
}
like image 172
Makyen Avatar answered Oct 16 '22 22:10

Makyen