替换Firefox扩展中的网站背景色



我正在构建一个Firefox扩展,它需要替换一个网站上的主体背景颜色。我对主要在Firefox 4上工作的方法感兴趣,与旧版本的Firefox的兼容性并没有那么重要。

我已经在Chrome、Opera和Safari扩展中做到了这一点,但经过几个小时的阅读和尝试,我无法在Firefox扩展中做到同样的事情。请帮忙。

我提前为这么长的帖子道歉,我尽量缩短它。

到目前为止我尝试了什么:


1.DOMContent Loaded

这个方法确实替换了颜色,但做得太晚了,Firefox首先显示原始颜色,然后用我的颜色替换它。我的功能似乎不会执行,直到该网站的adsense或facebook小部件完成它们的工作。若用户有某种广告屏蔽程序,它会正常工作,但这显然对我的扩展没有任何意义。

gBrowser.addEventListener("DOMContentLoaded", my_function, true);
my_function: function(event)
{
    var doc = event.originalTarget;
    doc.body.style.background = "#f00";
}


2.观察员

我尝试了这三种观察者类型:

  • 全局创建的chrome文档
  • 全局创建的内容文档
  • 插入的文档元素

我无法从任何列出的观察者访问body元素。

Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService).addObserver(
{
    observe: function(aSubject, aTopic, aData)
    {
        var doc = aSubject;
        // doc.location     - contains the url
        // doc          - [object XrayWrapper [object Window]]
        // doc.document     - [object XrayWrapper [object HTMLDocument]]
        // doc.document.body    - null
        doc.document.body.style.background = "#f00";    // this will obviously not work because body is not yet created or I'm looking in the wrong place
    }
}, "content-document-global-created", false);


3.具有NOTIFY_STATE_DOCUMENT的WebProgressListener

从STATE_TRANSFERRING我无法访问正文,从STATE_STOP太晚了。

browser.webProgress.addProgressListener(this, browser.webProgress.NOTIFY_STATE_DOCUMENT);
onStateChange: function(aWebProgress, aRequest, aFlag, aStatus)
{
    var doc = aWebProgress.DOMWindow;
    if (aFlag & Components.interfaces.nsIWebProgressListener.STATE_TRANSFERRING)
    {
        // doc.document.body    - null
        doc.document.body.style.background = "#f00";    // again this will obviously not work because body is not yet created or I'm looking in the wrong place
    }
    if (aFlag & Components.interfaces.nsIWebProgressListener.STATE_STOP)
    {
        // doc.document.body    - [object XrayWrapper [object HTMLBodyElement]]
        doc.document.body.style.background = "#f00";    // works but the same way DOMContentLoaded does, too slow
    }
}


4.具有NOTIFY_PROGRESS(或NOTIFY_STATE_REQUEST或NOTIFY_STATE_ALL)的WebProgressListener

这确实会立即改变颜色,但我为用户访问的每个网站和资源都收到了太多事件,所以我不愿意用它来做一件简单的事情,比如只为一个网站更改背景颜色。

browser.webProgress.addProgressListener(this, browser.webProgress.NOTIFY_PROGRESS);
onProgressChange: function(aWebProgress, aRequest, curSelf, maxSelf, curTot, maxTot)
{
    var doc = aWebProgress.DOMWindow;
    doc.document.body.style.background = "#f00";
}



有没有其他方法可以让我在创建body元素后立即访问它?或者可能有其他方法来更改网页样式(当然不涉及其他扩展)?我可以以某种方式将NOTIFY_PROGRESS侦听器连接到一个网站吗?

最后我做了一些对性能没有太大影响的东西,它立即改变了背景颜色。

我制作了两个侦听器:NOTIFY_LOCATIONNOTIFY_PROGRESS。我使用第一个(NOTIFY_LOCATION)来查看用户何时打开我试图更改颜色的网站,一旦用户打开该网站,我就会在该选项卡上设置NOTIFY_PROGRESS侦听器。从NOTIFY_PROCESS侦听器内部,我会检查body元素的存在,一旦body可以访问,我就会设置颜色并删除NOTIFY_PRODUCTESS侦听器,因为我不再需要它了。

listener_location =
{
    init: function()
    {
        gBrowser.browsers.forEach(function(browser)
        {
            browser.webProgress.addProgressListener(this, browser.webProgress.NOTIFY_LOCATION);
        }, this);
        gBrowser.tabContainer.addEventListener("TabOpen", this, false);
        gBrowser.tabContainer.addEventListener("TabClose", this, false);
    },
    uninit: function()
    {
        gBrowser.browsers.forEach(function(browser)
        {
            browser.webProgress.removeProgressListener(this);
        }, this);
        gBrowser.tabContainer.removeEventListener("TabOpen", this, false);
        gBrowser.tabContainer.removeEventListener("TabClose", this, false);
    },
    handleEvent: function(aEvent)
    {
        var tab = aEvent.target;
        var webProgress = gBrowser.getBrowserForTab(tab).webProgress;
        if (aEvent.type === "TabOpen")
        {
            webProgress.addProgressListener(this, webProgress.NOTIFY_LOCATION);
        }
        else
        {
            webProgress.removeProgressListener(this);
        }
    },
    QueryInterface: function(aIID)
    {
        if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
            aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
            aIID.equals(Components.interfaces.nsISupports))
            return this;
        throw Components.results.NS_NOINTERFACE;
    },
    onLocationChange: function(aProgress, aRequest, aURI)
    {
        if (aURI.host.indexOf("www.example.com") !== -1)
        {
            aProgress.addProgressListener(listener_progress, aProgress.NOTIFY_PROGRESS);
        }
    }
};
listener_location.init();

listener_progress =
{
    QueryInterface: function(aIID)
    {
        if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
            aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
            aIID.equals(Components.interfaces.nsISupports))
            return this;
        throw Components.results.NS_NOINTERFACE;
    },
    onProgressChange: function(aWebProgress, aRequest, curSelf, maxSelf, curTot, maxTot)
    {
        if (aWebProgress.DOMWindow.document.body)
        {
            aWebProgress.removeProgressListener(this);  // remove listener
            var doc = aWebProgress.DOMWindow.document;
            doc.body.style.background = "#f00";     // set color
        }
    }
};


如果其他人试图使用此代码,阅读以下内容可能会很有用:https://developer.mozilla.org/en/XUL_School/Intercepting_Page_Loadshttps://developer.mozilla.org/en/Code_snippets/Progress_Listenershttps://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIWebProgressListener

在显示body元素之前,您可能无法掌握它,因此您可以更改CSS样式。另一种选择是向文档样式表添加一个新规则,您应该能够通过web进度侦听器中的document.styleSheets来执行此操作。只需添加一条规则(必要时使其变得重要),强制将主体的背景设置为所需的颜色,并在显示主体时应用该规则。

最新更新