我正在创建一个firefox扩展,它允许操作员执行修改HTML文档内容的各种操作。操作员不编辑HTML,他们采取其他操作,我的扩展程序通过插入元素,添加属性等来修改文档。
当操作员完成后,他们需要能够将HTML文档保存为文件(或让我的扩展名将其发送到互联网目的地,但这不是必需的,因为他们可以通过电子邮件发送保存的文件)。
我想也许我的扩展程序中的javascript代码所做的更改会反映在HTML文档中,但是当我要求firefox浏览器在进行修改后“查看源代码”时,会显示原始的HTML文本。
我的问题是:
#1:操作员使用我的扩展程序进行的所有更改来保存HTML文档的最简单方法是什么?
#2:扩展程序中javascript代码处理HTML文档内容并写入本地磁盘上的HTML文件的最简单方法是什么?
#3:保存的文件中是否有任何有效的HTML内容无法准确表示?
#4:TreeWalker是解决方案的一部分(见下文)?
到目前为止,我的研究得出了一些观察结果:
我已经阅读了TreeWalker对象,它似乎为扩展程序提供了一种相当轻松的方式来遍历HTML文档中的所有内容(?或几乎所有内容?)。但是它是否暴露了一切,所以原始(和我的修改)中的所有东西都可以保存而不会丢失任何重要的东西?
TreeWalker是否以“正确的顺序”遍历HTML文档---我的扩展生成原始和/或修改过的HTML文档所需的顺序?
这些问题有什么模糊或棘手的问题吗?
答案 0 :(得分:1)
好的,所以我假设您可以访问页面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中的任何位置插入此标记,并在用户单击该文件时下载该文件。
注意:这有点像黑客,这会在a标签中注入整个文件的html,理论上它应该适用于任何up to date browser(除了惊喜,IE)。有更稳定和更少的hacky方式,例如将其存储在文件系统API文件中,然后下载该文件。
修改:document.querySelectorAll
行访问页面DOM。要使其正常工作,document
必须可访问。你说你正在修改DOM,所以应该已经在那里。确保您在页面上添加代码而不是扩展代码。此代码与DOM修改代码位于同一位置,而不是无法访问DOM的扩展页。
至于a
标签,它将被插入页面中。我跳过了这些步骤,因为我认为你已经知道如何操作DOM,也因为我不知道你想在哪里添加链接。您也可以跳过单击链接的用户操作,但这是一个黑客攻击,只适用于现代浏览器。您可以在原始页面的某处将a
标记插入用户无法看到的位置,然后调用a.click()
函数模拟链接上的点击事件。但这不是一种合法的方式,我个人只在我的练习项目中使用它来调用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();
答案 1 :(得分:0)
仅使用Web API没有简单的方法,至少当您希望结果不会省略doctype或comments等内容时。你仍然可以自己编写一个序列化程序,经过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
,然后使用file stream或完全异步OS.File
API等实际编写文件
答案 2 :(得分:0)
看起来我回答了我自己的问题,感谢mozilla #extdev IRC中的某个人。
我被“观察源”完全伪造了。当我在“查看源”显示的窗口中没有看到我的修改时,我认为浏览器不会提供信息。
然而,猜猜是什么?当我“归档”===>> “将页面保存为...”,然后使用纯文本编辑器检查页面内容......果然,其中包含我的firefox扩展所做的修改!惊喜!
答案 3 :(得分:-1)
浏览器没有对本地文件系统的直接写入权限。唯一的读取访问权限是明确提供file:// URL(参见下面的注释1)
在您的情况下,我们明确谈论javascript - 它可以读写cookie和本地存储。它还可以将东西发送回服务器并检索它,例如使用AJAX。
您放入本地存储/ cookie的内容实际上无法被其他程序(例如电子邮件客户端)访问。
可以创建非常长的mailto:URL(参见注释2),但只处理电子邮件中的内联内容,并且您将遇到各种您尚未准备好处理的编码问题。 / p>
因此我建议通过AJAX追求存储服务器端 - 一旦你有了这个分类/工作,就看看本地存储。
注1:这不是严格意义上的。受信任的,已签名的JavaScript可以访问可能包含直接文件访问权限的其他功能。
注2 :(限制取决于浏览器和电子邮件客户端 - Lotus Notes truncaets内容相当多)