带有多个窗口的空白Firefox插件面板页面

时间:2015-06-09 13:13:37

标签: firefox-addon firefox-addon-sdk

我已按照MDN's document创建了一个切换按钮插件。

除了一个问题外,一切正常:

  1. 打开第二个浏览器窗口(cmd + n或ctrl + n),然后点击那里的切换按钮
  2. 单击原始浏览器窗口上的切换按钮,而不关闭第二个窗口上的切换按钮
  3. 切换按钮的面板变为空白,并显示以下错误消息:

    JavaScript错误:资源:///modules/WindowsPreviewPerTab.jsm,第406行:NS_ERR OR_FAILURE:组件返回失败代码:0x80004005(NS_ERROR_FAILURE)[nsIT askbarTabPreview.invalidate]

  4.   

    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();
    }
    

    完整的插件位于:https://goo.gl/9N3jle

    要重现:提取zip文件并$ cd testButton; cfx run并按照上述步骤操作。

    我真的希望有人可以帮助我。提前谢谢!

2 个答案:

答案 0 :(得分:1)

这是一个错误;你没有做错任何事。这是Windows焦点事件和面板事件之间的竞争条件,它可以防止面板的隐藏事件以某种方式正确发出。

在正确修复问题之前,您可以尝试使用解决方法进行缓解。我在错误中添加了一些解释:https://bugzilla.mozilla.org/show_bug.cgi?id=1174425#c2但简而言之,您可以尝试添加setTimeout以在显示面板时稍微延迟,以避免窗口焦点的竞争条件。类似的东西:

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

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

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

答案 1 :(得分:0)

我目前正在使用一种解决方法,每当用户按下工具栏按钮时,我就会动态创建一个新的Panel

它比100ms的解决方法更快,并且还处理用户在面板打开时完全关闭其中一个浏览器窗口的情况。 (在这种情况下,100ms解决方法失败,仍然显示一个空白面板。)

它的工作原理如下:

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();
}