我正在构建一个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_LOCATION和NOTIFY_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来执行此操作。只需添加一条规则(必要时使其变得重要),强制将主体的背景设置为所需的颜色,并在显示主体时应用该规则。