Firefox附加组件的pageshow事件在工作人员能够接收消息之前触发

时间:2014-08-07 12:58:10

标签: javascript firefox firefox-addon firefox-addon-sdk

我正在编写一个firefox插件,并在数组中跟踪每个页面的工作人员。除了管理此阵列所需的一些花哨的步法(如此处https://bugzilla.mozilla.org/show_bug.cgi?id=686035和此处Addon SDK - context-menu and page-mod workers所述),一切正常。我遇到的一个问题是,在收听标签pageshow事件(或工作人员自己的pageshow事件)时,回调似乎在工作人员开始之前触发实际准备好了在回调中检索页面的相应工作者并使用它来尝试向内容脚本发送消息时,我收到错误The page is currently hidden and can no longer be used until it is visible again.通常,我只是使用了setTimeout和咬我的牙齿,但这不适用于附加组件。什么是合适的解决方法?加载项主要部分的代码如下:

var { ToggleButton } = require('sdk/ui/button/toggle');
var panels = require('sdk/panel');
var tabs = require('sdk/tabs');
var self = require('sdk/self');
var pageMods = require('sdk/page-mod');
var ss = require('sdk/simple-storage');
var workers = [];

ss.storage.isPluginActive = ss.storage.isPluginActive || false;

var button = ToggleButton({
    id: 'tomorrowww',
    label: 'Tomorowww',
    icon: {
        '16': './icon-16.png',
        '32': './icon-32.png',
        '64': './icon-64.png'
    },
    onChange: handleButtonChange
});

var panel = panels.Panel({
    contentURL: self.data.url('panel.html'),
    contentScriptFile: self.data.url('panel-script.js'),
    onHide: handlePanelHide,
    width: 342,
    height: 270
});

panel.port.on('panel-ready', handlePanelReady);
panel.port.on('plugin-toggled', handlePluginToggled);
panel.port.on('link-clicked', handleLinkClicked);

pageMods.PageMod({
    include: ['*'],
    contentScriptFile: [self.data.url('CancerDOMManager.js'), self.data.url('content-script.js')],
    contentStyleFile: self.data.url('content-style.css'),
    onAttach: function (worker) {
        addWorker(worker);
        sendActiveState(ss.storage.isPluginActive);
    }
});

// move between tabs
tabs.on('activate', function () {
    sendActiveState();
});

// this actually fires before the worker's pageshow event so isn't useful as the workers array will be out of sync
//tabs.on('pageshow', function () {
//    sendActiveState();
//});

function addWorker (worker) {
    if(workers.indexOf(worker) > -1) {
        return;
    }

    worker.on('detach', handleWorkerDetach);
    worker.on('pageshow', handleWorkerShown);
    worker.on('pagehide', handleWorkerHidden);
    workers.push(worker);
}

function handleWorkerDetach () {
    removeWorker(this, true);
}

function handleWorkerShown () {
    addWorker(this);

    // back / forward page history
    // trying to send the state here will trigger the page hidden error
    sendActiveState();
}

function handleWorkerHidden () {
    removeWorker(this);
}

function removeWorker (worker, removeEvents) {
    var index = workers.indexOf(worker);

    removeEvents = removeEvents || false;

    if(index > -1) {
        if(removeEvents) {
            worker.removeListener('detach', handleWorkerDetach);
            worker.removeListener('pageshow', handleWorkerShown);
            worker.removeListener('pagehide', handleWorkerHidden);
        }

        workers.splice(index, 1);
    }
}

function getWorkersForCurrentTab () {
    var i;
    var tabWorkers = [];

    i = workers.length;

    while(--i > -1) {
        if(workers[i].tab.id === tabs.activeTab.id) {
            tabWorkers.push(workers[i]);
        }
    }

    return tabWorkers;
}

function handlePanelReady () {
    setActive(ss.storage.isPluginActive);
}

function setActive (bool) {
    ss.storage.isPluginActive = bool;
    panel.port.emit('active-changed', bool);
    sendActiveState();
}

function sendActiveState () {
    var tabWorkers = getWorkersForCurrentTab();
    var i = tabWorkers.length;

    while(--i > -1) {
        tabWorkers[i].port.emit('toggle-plugin', ss.storage.isPluginActive);
    }
}

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

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

function handleLinkClicked (url) {
    if(panel.isShowing) {
        panel.hide();
    }

    tabs.open(url);
}

function handlePluginToggled (bool) {
    if(panel.isShowing) {
        panel.hide();
    }

    setActive(bool);
}

2 个答案:

答案 0 :(得分:0)

尝试在page-mod

中使用contentScriptWhen: "start"

答案 1 :(得分:0)

我正在处理类似的问题。我认为通过将侦听器放在 content 脚本而不是 addon 脚本中,我可以按照我想要的方式工作。我在窗口上监听事件,然后从内容脚本向我的插件脚本发出消息,然后我的插件脚本将消息发送回内容脚本,并附带插件脚本所需的信息。

在我的代码中,我正在更新内容脚本中的首选项,以确保选项卡在更改时始终具有最新设置,只有插件脚本可以侦听prefs更改事件。

此特定代码段将侦听页面从历史记录(即后退或前进按钮)导航时,将通知插件脚本,插件脚本将获取最新的首选项,然后将其发送回一个在内容脚本中监听的端口。

内容脚本:

window.onpageshow = function(){
    console.log("onpageshow event fired (content script)");
    self.port.emit("triggerPrefChange", '');    
};

插件脚本(例如,main.js:

worker.port.on("triggerPrefChange", function() {
      console.log("Received request to triggerPrefChange in the addon script");
      worker.port.emit("setPrefs", prefSet.prefs);
  });

由于事件是从DOM事件触发的,因此必须显示该页面。我不确定在 addon 脚本中收听pageshow事件是否正在按照我们的想法进行。