在向用户显示页面之前拦截和修改DOM

时间:2015-02-17 23:28:59

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

我正在尝试创建一个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&#39;在运行中&#39; (或事件阻止在加载所有页面之前显示任何类型的页面。)

我已经检查了cloud-to-butt扩展程序,因为它会动态修改页面,但我甚至无法让它工作:当作为pageMod附加在{{1代码失败了:

start

因为 document.getElementById('appcontent').addEventListener('DOMContentLoaded', function(e) 返回null。

我非常感谢一些指示:是否有可能,如何附加脚本,如何拦截HTML并在经过一些修改后将其发送回去。

编辑: 好的,所以我认为我能够拦截数据:

document.getElementById('appcontent')

现在在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('')); } } 我想对数据做些什么并将其输出回原来的位置......

请注意,这适用于字符串而不是DOM,因此它并不完美,但它是一个可以开始的地方:)

EDIT2:

嗯,我得到了它的工作,虽然我有一种感觉,我并不是真的应该这样:

onStopRequest

3 个答案:

答案 0 :(得分:8)

  

我的问题是:我可以在页面开始显示之前对DOM执行修改(所以:服务器返回的HTML文档)吗?

是的,javascript执行在第一次呈现页面之前开始。 DOM解析器会通知mutation observers,因此您可以在解析器添加元素后立即删除元素。

即使在加载了contentScriptWhen: "start"的内容脚本中,您也可以注册变异观察者,因此在渲染之前,应该通知他们在渲染之前添加到树中的所有元素,因为观察者通知是在微任务队列中执行的在宏任务队列上。

  

但我甚至无法让它工作:当作为pageMod连接启动时代码失败:   document.getElementById('appcontent').addEventListener('DOMContentLoaded', function(e)

当然。您不应该假设任何特定元素 - 甚至<body>标记 - 在页面加载期间早期已经可用。您将不得不等待它们可用。

DOMContentLoaded事件可以简单地在document对象上注册。我不知道你为什么要在某个元素上注册它。

  

(或事件阻止在加载所有页面之前显示任何类型的页面。)

你真的不想这样做,因为它会增加页面加载时间,从而降低网站的响应能力。

答案 1 :(得分:1)

strdup

答案 2 :(得分:0)

如果你想在执行任何脚本之前进入它,那么这里有文档观察者:https://developer.mozilla.org/en-US/docs/Observer_Notifications#Documents,例如content-document-global-created