Blank Firefox add-ons panel page with multiple windows

I followed the MDN document to create an add-on button switch.

Everything works fine except for one problem:

  • Open a second browser window (cmd + n or ctrl + n) and click the toggle button there
  • Click the toggle button in the original browser window without closing the toggle button in the second window
  • the toggle button bar is empty with the following error message:

    JavaScript error: resource: ///modules/WindowsPreviewPerTab.jsm, line 406: NS_ERR OR_FAILURE: Component return code: 0x80004005 (NS_ERROR_FAILURE) [nsIT askbarTabPreview.invalidate]

problem screenshot

// ./lib/main.js
var { ToggleButton } = require("sdk/ui/button/toggle");
var panels = require("sdk/panel");
var self = require("sdk/self");

var buttonIndex = 0;
var lastKnownButtonIndex = 0;

var button = ToggleButton({
    id: "button",
    label: "my button",
    icon: {
        "16": "./icon-16.png"
    },
    onClick: handleChange,
});

var panel = panels.Panel({
    contentURL: self.data.url("menu.html"),
    onHide: handleHide
});

function handleChange(state) {
    if (state.checked) {
        panel.show({
            position: button
        });
    }
}

function handleHide() {
  button.state('window', {checked: false});
}

function assignButtonIndex() {
    return (buttonIndex++).toString();
}

      

The full addon is here: https://goo.gl/9N3jle

Playback: extract the zip file and $ cd testButton; cfx run

and follow these steps.

I really hope someone can help me. Thank you in advance!

+3


source to share


2 answers


This is mistake; you are not doing anything wrong. This is a race condition between window focus events and a panel event, which prevents the hidden panel event from somehow being correctly emitted.

You can try to mitigate the problem until it is fixed. I added some explanation to the bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1174425#c2 , but in short, you can try adding setTimeout

to delay the bit when the panel is shown to avoid the racing state with focus of the window. Something like:



const { setTimeout } = require("sdk/timers");

/* ... your code here ... */    

function handleChange(state) {
  if (state.checked) {
    setTimeout(() => panel.show({ position: button }), 100);
  }
}

      

+1


source


I am currently using a workaround where I dynamically create a new Panel

one every time the user clicks a button on the toolbar.

This is faster than the 100ms workaround and also handles the scenario where the user completely closes one of the browser windows when the panel is open. (The 100ms workaround doesn't work in this case, and the empty pane is still displayed.)



It works like this:

let myPanel = null;

const toolbarButton = ToggleButton({
    ...,
    onChange: function (state) {
        if (state.checked) {
            createPanel();
        }
    }
});

function createPanel(){   
    // Prevent memory leaks
    if(myPanel){
        myPanel.destroy();
    }

    // Create a new instance of the panel
    myPanel = Panel({
        ...,
        onHide: function(){
            // Destroy the panel instead of just hiding it.
            myPanel.destroy();
        }
    });

    // Display the panel immediately
    myPanel.show();
}

      

0


source







All Articles