2014-10-19 168 views
0

我有一个Firefox覆盖扩展和侧栏中的一棵树。 如何保持树状态在多个窗口中同步? 例如在第一个窗口中添加了新的项目树,如何更新其他窗口中的树?Firefox扩展:共享状态

如果有人可以显示最少的代码(使用代码模块,观察者,广播或其他),请帮助。

我看过类似的问题,但它并没有帮助: Firefox extension - Share common state between two or more windows

+0

我这样做的方式是使用'Services.wm.getEnumerator('navigator:browser')'枚举窗口,并在每次更新一个窗口时更新所有窗口。如果你想要定位所有的窗口,不只是浏览器的窗口'getEnumerator(null)' – Noitidart 2014-10-20 15:09:28

回答

1

在你参考这个问题的答案是好的,但短期上的解释。您应该阅读它链接的参考。我在这里复制了这些链接。

保持窗口上下文以外状态信息的一种方法是使用JavaScript code modules(JSM)。部分Sharing objects using code modules简要介绍了如何做到这一点。一旦建立了JSM以共享数据,只需通知每个窗口已做出更改并且它应更新显示的状态。这很容易通过使用您定义的事件来完成。所有的侧边栏在他们的窗口中倾听特定的事件。然后JSM中有一个函数在所有的窗口中运行,表明它们需要更新。

信号可能看起来像代码:

Components.utils.import("resource://gre/modules/Services.jsm"); 

function forEachOpenWindow(todo) { 
    // Apply a function to all open browser windows 
    var windows = Services.wm.getEnumerator("navigator:browser"); 
    while (windows.hasMoreElements()) { 
     todo(windows.getNext().QueryInterface(Components.interfaces.nsIDOMWindow)); 
    } 
} 

function signalUpdateNeeded(window){ 
    let event = window.document.createEvent("Event"); 
    event.initEvent("myExtensionName-UpdateAvailable",false,false); 
    window.dispatchEvent(event); 
} 

function sendUpdateAvailableToAllWindows(){ 
    forEachOpenWindow(signalUpdateNeeded); 
} 

然后在侧边栏的代码:

//This imports your JSM, it does not need the .jsm extension, you can use 
// whatever extension you want. 
Components.utils.import("chrome://MyExtension/content/moduleName.jsm"); 

window.addEventListener("myExtensionName-UpdateAvailable", 
          updateDataFromModule, false); 
//Instead you may need the following (or another way to get to the 
// top window). What is actually needed will depend on the context in 
// which your sidebar code is running. You should see below for code to 
// access the main browser window from within a sidebar. 
//window.top.addEventListener("myExtensionName-UpdateAvailable", 
//       updateDataFromModule, false); 


function updateDataFromModule(){ 
    //Whatever it is you need to do here. 
    mylocalVariable = myExtensionModule.dataStructure.whatever; 
} 

重构上面的第一个代码段,这样它看起来是一个模块使用一个变量来减少命名空间混乱。该模块的代码可能是这样的:

var EXPORTED_SYMBOLS = [ "myExtensionModule" ]; 
Components.utils.import("resource://gre/modules/Services.jsm"); 

var myExtensionModule = { 
    dataStructure: { 
     whatever: true, 
     you: 1, 
     want: ["here.", "It", "is", "your", "data."] 
    }; 

    forEachOpenWindow: function(todo){ 
     // Apply a function to all open browser windows 
     var windows = Services.wm.getEnumerator("navigator:browser"); 
     while (windows.hasMoreElements()) { 
      todo(windows.getNext() 
         .QueryInterface(Components.interfaces.nsIDOMWindow)); 
     } 
    }, 

    signalUpdateNeeded: function(window){ 
     let event = window.document.createEvent("Event"); 
     event.initEvent("myExtensionName-UpdateAvailable",false,false); 
     window.dispatchEvent(event); 
    }, 

    sendUpdateAvailableToAllWindows: function(){ 
     this.forEachOpenWindow(this.signalUpdateNeeded); 
    } 
} 

我没有真正测试过,所以可能会有一些错误。

要么让您的侧边栏代码访问主浏览器窗口,要么JSM代码找到您的代码所在的侧栏(以便发送或收听事件)可能比您想象的要复杂一些。你应该看到Working with windows in chrome code。具体而言,Accessing the elements of the top-level document from a child window。这部分提供了下面的代码来从一个侧边栏内访问主浏览器窗口中:

var mainWindow = window 
        .QueryInterface(Components.interfaces.nsIInterfaceRequestor) 
        .getInterface(Components.interfaces.nsIWebNavigation) 
        .QueryInterface(Components.interfaces.nsIDocShellTreeItem) 
        .rootTreeItem 
        .QueryInterface(Components.interfaces.nsIInterfaceRequestor) 
        .getInterface(Components.interfaces.nsIDOMWindow); 

另一种方法是为您的JSM保持参考在数据结构上,所有的侧栏的将侦听的对象。这可能是它创建的一个对象。如果您确实使用这种方法并选择使用窗口,那么您需要确保在窗口关闭时释放引用的句柄。如果你不这样做,你最终可能会发生内存泄漏。