您的位置:首页 > 其它

使用 XUL 实现浏览器扩展,第 1 部分: 使用用户界面特性创建一个 Firefox 浏览器扩展

2009-01-16 14:08 706 查看
Mozilla 项目团队很早就决定标准化 C++ 中的核心开发,但是它需要创建一个组件系统 XPCOM(Cross Platform Component Object Model),用于在不同平台之间共享核心和扩展功能。它还开发了一种为这些组件设计用户界面的方法,其中使用了一种与平台无关的语言,称为 XUL(XML User Interface Language),读作 “zool”。在 XUL 中使用 XML 没有什么特别之处,团队本来要开发一套全新的语法 ,但是认为最好将 XUL 视为一种使用 XML 作为基本语法的编程语言。XUL 利用了一些现有 Web 技术,例如 ECMAcript(其 JavaScript 实现尤为出名)、DOM 和 CSS,因此,Web 开发人员应该可以轻松地掌握。其姊妹语言 XBL (eXtensible Bindings Language)用于控制 XUL 元素的动态行为。XUL 和 XBL 功能非常强大,足以在 Mozilla 组件的基础上开发功能完整的浏览器或者其他完整的跨平台应用程序,但是对于大多数开发人员来讲,XUL 更多地用于扩展或处理现有浏览器或其他用户程序的用户界面(XUL 针对这一用例进行了精心设计)。通常,在开发浏览器扩展时,大多数 Mozilla 浏览器的终极目标就是 Firefox,它是 Mozilla 的一个非常流行的独立浏览器。Firefox 使用 XUL 和 JavaScript 构建。它演示了 XUL 的强大功能,但也支持使用 XUL 构建的扩展。

本文囊括了使用用户界面特性创建大多数扩展所需的基本知识 — XUL、CSS、JavaScript 和 DOM。本文并不是对 XUL 的简介 — 您可以通过 参考资料 中的链接找到此类介绍。本文要求您了解该语言的基本概念并展示如何应用这些内容。您还需要了解 JavaScript、DOM 和 CSS 的基本知识。

XUL 提供了直接的方式

XUL 的优点之一就是,大部分情况下,Mozilla 浏览器处理它的方式与任何其他 Web 内容并无二致。这意味着,您可以在开发阶段快速进行测试和部署,然后考虑将开发成果正确打包为应用程序或完整的扩展。一些有用的工具可用于这类快速开发 — Ted Mielczarek 的 Extension Developer's Extension(参见 参考资料), 其中包括很多有用的工具,例如允许在线编辑和预览 XUL 的 Live XUL Editor 。他还在其 Web 站点中提供了一个非常简单的 XUL 页面来执行相同的功能(但不包括应用于通过 Web 加载的 XUL 的安全限制)。大部分情况下,我倾向于对 XUL 开发周期使用更为直接的方式:使用一个良好的文本编辑器进行编辑,并且编辑器最好能够提供可以简化 XML 编写的功能,然后将 XUL 文件直接加载到 Firefox 选项卡中即可。再次进行编辑,做出调整或修补,然后为文件重新加载页面。清单 1(stats.xul)是一个简单的 XUL 示例,演示了这种语言的一些功能。该示例允许您输入一个 URL 并在一个面板中查看结果 Web 页面,而在另一个面板查看页面的统计信息。

清单 1 (stats.xul). 简单的 XUL 示例

<?xml version="1.0"?>

<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"

id="statswindow" title="View Web page stats">

<vbox flex="1">

<hbox id="toppanel">

<label value="Enter a URL:"/>

<textbox id="url" flex="1" value="http://www.ibm.com/developerworks/web"/>

<button label="Go!"/>

</hbox>

<description value="Current page:"/>

<hbox flex="1">

<iframe id="contentview" src="http://www.ibm.com/developerworks/web" flex="2"/>

<vbox>

<groupbox>

<caption label="Stats"/>

<grid flex="1">

<columns>

<column flex="1"/>

<column flex="1"/>

</columns>

<rows>

<row>

<label value="Word count"/>

<textbox class="count" id="wordcount" value="N/A" readonly="true"/>

</row>

<row>

<label value="Character count"/>

<textbox class="count" id="charcount" value="N/A" readonly="true"/>

</row>

<row>

<label value="Element count"/>

<textbox class="count" id="elemcount" value="N/A" readonly="true"/>

</row>

</rows>

</grid>

</groupbox>

<spacer flex="1"/>

</vbox>

</hbox>

</vbox>

</window>

chrome://global/skin/
样式表声明使浏览器可以使用 chrome 包中的默认
global.css
,它提供了内置的 Firefox 感观,如果您安装了皮肤,则提供一些稍有不同的外观。该窗口使用一组嵌套的框来组织内容,但是我尽量避免对外观使用过多无用的内容(我将在下一节中进行介绍),而一直对 UI 元素进行逻辑分组。
iframe
元素类似于 HTML 中的同名元素,它将创建呈现相关 Web 页面的内容框架,默认为
http://www.ibm.com/developerworks/web
url textbox
的值与此相同。这些值互相匹配才能使默认视图对用户有意义,而目前它们之间还没有联系(我将在下一节实现)。
groupbox
可以方便地组织状态条目,每个条目都是只读的文本框,目前的默认值是一个虚拟值。清单 1 的结果是一个简单的静态窗口,由于使用了
iframe
,因此仍然提供了非常不错的结果。将其保存到文件 “stats.xul” 中并加载到任何 Mozilla 浏览器窗口。可以使用 “file:” URL 或者是 Firefox 上的 “Open File” 按钮。得到的显示结果应如图 1 所示。

图 1. 在 Firefox 浏览器窗口中加载清单 1



添加外观样式

您 可以在 XUL 中改变 UI 元素的位置,但是大多数情况下,窗口外观的具体细节最好交于样式表处理。与对 HTML 或其他 XML 应用 CSS 一样,对 XUL 应用 CSS 允许您控制常见的属性 — 颜色、字体、空间和大小。清单 2(stats.css)显示了一些声明,用于调整清单 1 中的外观。

清单 2(stats.css). 对清单 1 应用 CSS

window {

font-family: arial, "lucida console", sans-serif;

}

description {

padding: 5px;

color: blue;

}

#toppanel {

padding: 5px;

}

#contentview {

padding: 5px;

border: thin solid black;

}

.count {

width: 5em;

}

可以看到,样式表规则使用 ID、类和元素选择器匹配清单 1 的各部分内容。通过在 XUL 文件的顶部添加额外的声明便可应用这种样式表,如清单 3 所示,其中仅显示了文件进行更新(添加新的 CSS 声明)后的前四行内容。

清单 3. 使用新添的样式表声明更新清单 1 中前面几行内容

<?xml version="1.0"?>

<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

<?xml-stylesheet href="stats.css" type="text/css"?>

<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"

注意,我并没有删除对
chrome://global/skin/
的声明。您几乎总是需要这样做,并且浏览器将把全局的皮肤与更为具体的样式表结合起来。图 2 显示将一个使用样式表更新过的 XUL 窗口加载到 Firefox 中。

图 2. Firefox 浏览器显示使用 CSS 的 XUL 窗口










回页首
通过脚本驱动应用程序工作

开发这个示例 XUL 应用程序的最后一步是使控件可以工作。可以通过将控件与行为相绑定来实现。XUL 具有一种姊妹语言 XBL,它允许您通过声明执行大部分绑定,从而减少所需的脚本数量。但是本文将使用引用 JavaScript 函数的事件属性来实现绑定。

清单 4(stats-styled-scripted.xul). 使用 CSS 和脚本声明以及脚本 hook 属性更新后的清单 1

<?xml version="1.0"?>

<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

<?xml-stylesheet href="stats.css" type="text/css"?>

<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"id="statswindow" title="View Web page stats">

<script type="application/x-javascript" src="stats.js"/>

<vbox flex="1">

<hbox>

<label value="Enter a URL:"/>

<textbox id="url" flex="1" value="http://www.ibm.com/developerworks/web"/>

<button label="Go!" oncommand="change_url(event)"/>

</hbox>

<description value="Current page:"/>

<hbox flex="1">

<iframe id="contentview" src="http://www.ibm.com/developerworks/web" flex="2"/>

<vbox>

<groupbox>

<caption label="Stats"/>

<grid flex="1">

<columns>

<column flex="1"/>

<column flex="1"/>

</columns>

<rows>

<row>

<label value="Word count"/>

<textbox class="count" id="wordcount" value="N/A" readonly="true"/>

</row>

<row>

<label value="Character count"/>

<textbox class="count" id="charcount" value="N/A" readonly="true"/>

</row>

<row>

<label value="Element count"/>

<textbox class="count" id="elemcount" value="N/A" readonly="true"/>

</row>

</rows>

</grid>

</groupbox>

<spacer flex="1"/>

</vbox>

</hbox>

</vbox>

</window>


注意
window
内新增的
script
元素,以及对 “Go!” 按钮添加的属性 —
oncommand="change_url(event)"
。清单 5 显示的是所引用的 JavaScript 文件 “stats.js”。

清单 5(stats.js). 处理 “Go!” 按钮的 JavaScript 代码

//Invoked in response to a click on the "Go!" button

function change_url(event)

{

//Variables for convenient access to specific elements in the XUL

var urlbox = document.getElementById("url");

var contentview = document.getElementById("contentview");

var wordcountbox = document.getElementById("wordcount");

var charcountbox = document.getElementById("charcount");

var elemcountbox = document.getElementById("elemcount");

//Setting this attribute, happens to change the visible contents of the panel

contentview.setAttribute("src", urlbox.value);

//Fake up the update code for now, to allow running in Firefox

wordcountbox.previousSibling.value += " (fake)";

wordcountbox.value = "1000";

charcountbox.previousSibling.value += " (fake)";

charcountbox.value = "100";

elemcountbox.previousSibling.value += " (fake)";

elemcountbox.value = "10";

}

清单 4 将
change_url
函数绑定到对 “Go!” 按钮的单击事件中。该函数将接收关于单击的事件信息,不过本例中并没有使用到。全局对象
document
允许您使用 DOM 访问各种 XUL 元素,本例中使用的是
getElementById
,可根据惟一 ID 查找元素。XUL 元素当然具备 XML 属性,但是也提供了对象特性,并且某些时候即使这些属性和特性具有类似的名称,但进行查询和处理时却行为各异。例如,我使用代码
urlbox.value
获得 URL 文本框中的文本,而不是使用代码
urlbox.getAttribute("value")
。后者通常用于读取文本框的初始内容(“http://www.ibm.com/developerworks/web”),而不管用户登录页面后输入什么内容。类似地,如果希望通过代码更新此类文本框中的可见内容,您应该使用
urlbox.value = newvalue
而不是
urlbox.setAttribute("value", newvalue)
。在可以更新函数下方的 count 文本框的代码中,您可以看到这些规则的应用。XUL 参考文档中涵盖了所有这些详细内容,因此请仔细阅读有关所使用的 XUL 元素的内容。

安全性

有关属性和特性的注意事项也适用于
contentview.setAttribute("src", urlbox.value);
行。转到新 URL 的更为正确的方法是:
contentview.contentDocument.location.href = urlbox.value;
。但是这里存在一个问题。Firefox 对 XUL 文档提供的严格的安全模型意味着,如果您试图访问一些敏感的对象属性,包括
contentview.contentDocument
,JavaScript 将抛出一个异常。您需要使用 Error Console 窗口查看错误信息,这些错误可能含混不清并且没有具体说明,例如 “Error: uncaught exception: Permission denied to create wrapper for object of class UnnamedClass”。这是直接使用 XUL 的主要问题。在下一篇文章中,我将展示如何将本文中的粗糙内容调整为一个合适的 Firefox 扩展,它将通过实现正确的 chrome 注册绕过安全限制。目前,代码修改了未受限制的
contentview
(可以提供可见结果)的
src
属性,并对 count 文本框进行一些虚构的更改,以向您显示 XUL 脚本的基本设置。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐