【发布时间】:2015-04-18 20:10:55
【问题描述】:
我正在尝试创建一个 Firefox 插件(使用插件 SDK)来修改页面的显示方式,主要是作为培训/学习练习。
对于某些任务(例如用新功能扩充页面),使用pageMod 非常好。页面加载,我运行一些 JS 来显示/隐藏/添加元素。
我的问题是:我可以在页面开始显示之前对 DOM(即服务器返回的 HTML 文档)进行修改吗?
例如:服务器返回的页面是:
<html>
<body>
<table>
<tr>
<td>Item 1.1</td>
<td>Item 1.2</td>
<td>Item 1.3</td>
</tr>
<tr>
<td>Item 2.1</td>
<td>Item 2.2</td>
<td>Item 2.3</td>
</tr>
</table>
</body>
</html>
但我希望 FF 改为渲染:
<html>
<body>
<ul>
<li>Item 1.1, Item 1.2, Item 1.3</li>
<li>Item 2.1, Item 2.2, Item 2.3</li>
</ul>
</body>
</html>
在页面加载后执行此操作将首先显示表格,然后它会快速“闪烁”到列表中。它可能足够快,但如果我要将<img> 标记更改为<a>,例如防止(不需要)图像加载,这还不够。
我正在查看在 pageMod 中使用 contentScriptWhen: "start" 并尝试附加侦听器,但我只是看不出我如何能够“即时”修改 DOM(或事件阻止任何类型的页面显示在所有页面之前已加载)。
我已经检查了cloud-to-butt 扩展,因为它确实会即时修改页面,但我什至无法让它工作:当在start 上作为 pageMod 附加时,代码失败:
document.getElementById('appcontent').addEventListener('DOMContentLoaded', function(e)
因为 document.getElementById('appcontent') 返回 null。
我会非常感谢一些指点:是否可能,如何附加脚本,如何截取 HTML 并在经过一些修改后将其发送回去。
编辑: 好的,所以我认为我能够截取数据:
let { Ci,Cr,CC } = require('chrome');
let { on } = require('sdk/system/events');
let { newURI } = require('sdk/url/utils');
let ScriptableInputStream = CC("@mozilla.org/scriptableinputstream;1", "nsIScriptableInputStream", "init");
on('http-on-examine-response', function (event) {
var httpChannel = event.subject.QueryInterface(Ci.nsIHttpChannel);
var traceChannel = event.subject.QueryInterface(Ci.nsITraceableChannel);
if (/example.com/.test(event.subject.URI.spec)) {
traceChannel.setNewListener(new MyListener());
}
}, true);
function MyListener(downloader) {
this.data = "";
}
MyListener.prototype = {
onStartRequest: function(request, ctx) {
this.data = [];
},
onDataAvailable : function(request, context, inputStream, offset, count) {
var scriptStream = new ScriptableInputStream(inputStream);
this.data.push(scriptStream.read(count));
scriptStream.close();
},
onStopRequest: function(request, ctx, status) {
console.log(this.data.join(''));
}
}
现在在onStopRequest 中,我想对数据做一些事情并将其输出回原来的位置...
注意,这适用于字符串而不是 DOM,所以它并不完美,但它是一个开始的地方:)
编辑2:
嗯,我搞定了,虽然我觉得我不应该那样做:
onStopRequest: function(request, ctx, status) {
//var newPage = this.data.join('');
var newPage = "<html><body><h1>TEST!</h1></body></html>";
var stream = converter.convertToInputStream(newPage);
var count = {};
converter.convertToByteArray(newPage, count);
this.originalListener.onDataAvailable(request, ctx,
stream, 0, count.value);
this.originalListener.onStopRequest(request, ctx, status);
},
【问题讨论】:
-
我实际上最近不得不在一个 FF 扩展中做同样的事情,并决定在加载头部后添加一个隐藏整个身体的样式标签来“破解”它,然后修改HTML,完成后,删除样式标签,显示正文,不闪烁,问题解决。可能有更好的方法来做到这一点。
-
这是一个有趣的想法,将来可能会派上用场 :) 虽然我实际上正在寻找一种方法来 - 除其他外 - 删除一些脚本,删除一些图像(类似广告块) - 再次, amonsts others - 节省加载时间。
-
如果要截取数据并反馈修改后的数据使用nsITraceableChannel:github.com/Noitidart/demo-nsITraceableChannel
标签: javascript firefox-addon firefox-addon-sdk mozilla