firefox扩展可以修改HTML文档的DOM,然后保存为HTML
can firefox extension modify DOM of HTML document then save as HTML?
我正在创建一个firefox扩展,它允许操作员执行修改HTML文档内容的各种操作。操作员不编辑HTML,他们执行其他操作,我的扩展插件通过插入元素、添加属性等方式修改文档。
操作员完成后,他们需要能够将HTML文档保存为文件(或者让我的扩展名将其发送到互联网目的地,但这不是必需的,因为他们可以通过电子邮件发送保存的文件)。
我以为扩展中javascript代码所做的更改可能会反映在HTML文档中,但当我要求firefox浏览器在进行修改后"查看源代码"时,它会显示原始HTML文本。
我的问题是:
#1:对于操作员来说,保存HTML文档以及我的扩展名所做的所有更改最简单的方法是什么?
#2:我的扩展中的javascript代码处理HTML文档内容并写入本地磁盘上的HTML文件的最简单方法是什么?
#3:是否有任何有效的HTML内容无法在保存的文件中准确表示?
#4:TreeWalker是解决方案的一部分吗(见下文)?
到目前为止,我的研究有几个观察结果:
我读过关于TreeWalker对象的文章,它似乎为扩展提供了一种相当轻松的方式来遍历HTML文档中的所有内容(?或几乎所有内容?)。但是,它是否公开了所有内容,以便在不丢失任何重要内容的情况下保存原始内容(以及我的修改)中的所有内容?
TreeWalker是否按照"正确的顺序"遍历HTML文档——这是我的扩展生成原始和/或修改的HTML文档所必需的顺序?
这些问题有什么晦涩难懂的地方吗?
好的,所以我假设您可以访问页面DOM。你需要做的基本上是对dom进行更改,然后获得所有的dom代码并将其保存为一个文件。以下是如何下载页面的html代码。这将创建一个a
标记,用户需要单击该标记才能下载文件。
var a = document.createElement('a'), code = document.querySelectorAll('html')[0].innerHTML;
a.setAttribute('download', 'filename.html');
a.setAttribute('href', 'data:text/html,' + code);
现在,您可以在DOM中的任何位置插入一个标记,当用户单击它时,文件就会下载
注意:这是一种黑客攻击,它将文件的整个html注入一个标签中,理论上它应该在任何最新的浏览器中工作(除了IE)。有一些更稳定、更不易破解的方法,比如将其存储在API文件系统中,然后下载该文件。
编辑:document.querySelectorAll
行访问页面DOM。要使其工作,document
必须是可访问的。您说您正在修改DOM,所以它应该已经存在了。请确保您在页面上添加的是代码,而不是扩展代码。此代码将与DOM修改代码位于同一位置,而不是不能访问DOM的扩展页。
至于a
标签,它将被插入到页面中。我跳过了这些步骤,因为我认为您已经知道如何操作DOM,也因为我不知道您想在哪里添加链接。你也可以跳过用户点击链接的操作,但这是一种黑客行为,只适用于现代浏览器。您可以在原始页面中用户看不到的地方插入a
标记,然后调用a.click()
函数来模拟链接上的单击事件。但这不是一种合法的方式,我个人只在我的练习项目中使用它来呼叫点击事件听众。
我只能在chrome上测试这个,而不能在FF上测试,但尝试一下这个代码,这甚至不需要添加到DOM的链接。您需要将其添加到DOM操作代码旁边。如果运气好的话,这会起作用:)
var a = document.createElement('a'), code = document.querySelectorAll('html')[0].innerHTML;
a.setAttribute('download', 'filename.html');
a.setAttribute('href', 'data:text/html,' + code);
a.click();
只有web API才能实现这一点,至少当您想要一个不省略doctype或注释等内容的结果时。您仍然可以自己编写一个序列化程序,通过document.childNodes
并根据节点类型(Element.outerHTML
、Comment.data
等)进行序列化。
幸运的是,你正在编写一个Firefox插件,所以你可以访问更多(强大)的东西。
虽然仍然不是100%完美,但nsIDocumentEncoder
实现将产生相当不错的结果,这最多只会在一些空白和显式字符集声明方面有所不同(其他都是错误)。以下是如何使用此组件的示例:
function serializeDocument(document) {
const {
classes: Cc,
interfaces: Ci,
utils: Cu
} = Components;
let encoder = Cc['@mozilla.org/layout/documentEncoder;1?type=text/html'].createInstance(Ci.nsIDocumentEncoder);
encoder.init(document, 'text/html', Ci.nsIDocumentEncoder.OutputLFLineBreak | Ci.nsIDocumentEncoder.OutputRaw);
encoder.setCharset("utf-8");
return encoder.encodeToString();
}
如果你正在编写一个SDK插件,那么随着SDK抽象掉一些重要的东西,事情会变得更加复杂。您需要浏览chrome
模块,还需要自己找出活动窗口和选项卡。像Services.wm.getMostRecentWindow("navigator:browser").content.document
(Services.jsm)这样的东西应该可以做到这一点。
在XUL覆盖加载项中,content.document
应该足以获取当前活动选项卡的文档,并且您已经拥有Components
访问权限。
尽管如此,您还是需要让用户选择一个文件目的地,通常是通过nsIFilePicker
,然后通过使用文件流或完全异步的OS.File
neneneba API来实际写入文件。
多亏了mozilla#extdev IRC中的某个人,我似乎可以回答自己的问题了。
我完全被"视图源"骗了。当我在"查看源代码"显示的窗口中没有看到我的修改时,我认为浏览器不会提供信息。
然而,你猜怎么着?当我"file"===>>"将页面另存为…"时,请使用纯文本编辑器检查页面内容。。。果不其然,其中包含了我的firefox扩展所做的修改!惊喜
浏览器无法直接写入本地文件系统。它唯一的读取访问权限是当显式提供文件时://URL(见下面的注释1)
在您的案例中,我们明确讨论的是javascript,它可以读写cookie和本地存储。它还可以将内容发送回服务器并检索,例如使用AJAX。
你放在本地存储/cookie中的东西实际上是其他程序(如电子邮件客户端)无法访问的。
可以创建很长的mailto:URL(请参阅注释2),但只处理电子邮件中的内联内容,您将遇到各种尚未准备好处理的编码问题。
因此,我建议通过AJAX实现存储服务器端,并在整理/工作后查看本地存储。
注1:这并非完全正确。受信任的签名javascript可以访问其他功能,可能包括直接文件访问。
注2:(限制取决于浏览器和电子邮件客户端-Lotus Notes截断了大量内容)
- 如何使用JavaScript在没有html dom的情况下隐藏html元素
- 如何序列化包括影子 DOM 在内的 HTML DOM
- 通过Java加载XML并制作HTML DOM的一部分
- 以非像素为单位获取HTML DOM元素的CSS高度,在我的例子中是英寸
- HTML DOM Text() nodes
- 递归单步执行 HTML DOM 并打印属性
- 从自身获取对脚本作为 HTML DOM 元素的引用
- 我可以将 HTML 字符串分配给 HTML DOM 节点的内部 HTML 属性吗?
- Javascript HTML DOM select
- 如何反转 JavaScript 变量中 HTML DOM 元素的顺序
- 在 HTML DOM 元素下添加 javascript 文件或 css 文件
- HTML DOM - element.appendChild() 的行为不像我期望的那样
- HTML DOM 使用 AngularJS ng-if 函数
- PHP 简单 HTML DOM 和下拉元素已选选项
- 将 HTML DOM 保存到服务器上的文件
- 为什么我的 HTML 按钮刷新页面?/为什么我不能让我的新 HTML DOM 元素插入到我的页面中
- 节点上的 d3 事件处理程序不在 HTML DOM 中
- 如何转换 HTML DOM 结构
- HTML/DOM:鼠标事件更改按钮
- HTML DOM alerting style.width