Hello World
来源:百度文库 编辑:神马文学网 时间:2024/04/29 15:52:21
——开发你的第一个Firefox扩展
刘文懋
Why Firefox?
如果有人问我为什么用Firefox[1],首先毫无疑问的是它代表了开放和自由的精神,其次嘛,我会说是它的可扩展性。
Firefox最激动人心的特点就是它提供了开放的接口,你可以使用这些接口来做各种应用,完成各种各样的功能。你应该不曾给IE添点什么吧,微软不见得这么大方能告诉你什么有用的东西。他最慷慨的事就是给你一个COM组件,记得我对IE的最高级的应用,就是在一次网络大作业中,把整个IE嵌在我的程序里,仅此而已。而Firefox则不同了,当你看到了Fireftp就知道我在说什么了。
请合上你的下巴,这没有什么值得惊讶的。这就是Firefox,中间那个cool的ftp工具只是它的一个扩展(Extesion)而已。
想做一个这样的东东吗?我不会告诉你到底有多难,因为这不是我开发的,有兴趣的话你可以自己试一试,网址是http://fireftp.mozdev.org/ 。
类似的扩展还有很多,你可以到mozilla的扩展库去看看,据官方统计,到2005年11月9日,(忘了告诉你了,2004年11月9日是Firefox的诞生日,也就是说它还只是一个小baby),用户至少可以使用700个扩展(Extension)或者附件(Add-on)。可见Firefox的扩展发展是多么的迅速!
以前我在99%的时间内使用Firefox,另外1%的时间使用IE浏览一些不遵从W3C标准而非用IE不可的垃圾网站,我们学校的BBS很不幸地成为其中一员。但是现在我在100%的时间内使用Firefox,这归功于一个ie tab[2]的Firefox扩展。所幸随着网络标准的日渐被重视,Firefox有可能会支持所有的网站。 :)
好了,说了这么多Firefox扩展的好处,是不是有点心动了呢?那么就用一个Hello World来开始我们的第一个Firefox扩展吧。别说我太不in了,毕竟hello world总是最容易让我们使所有编程语言的开场白,不是吗?
Here we go!
认识Firefox的扩展
Firefox扩展的功能
从功能来说,Firefox扩展应该是用户和浏览器内核交互的一种体系结构。扩展可以满足用户一些特定的需要,实现特定的功能。开发者可以使用内核提供的一些用户接口,编写自己的实现代码,完成自己设想的功能。
Firefox扩展的格式
从开发的角度来讲,Firefox的扩展是一个文件目录的集合,它们按照一定格式和规范编写和排布的。最终,发布给用户的是一个xpi包。别感到奇怪,这个xpi文件和那些jar[3]的文件一样,都是zip格式的压缩文件。所以这下你懂了吧,把你做完的文件按照zip格式压缩一下就成了我们的扩展包了。
那么究竟具体的xpi文件中是什么情景的?解开我提供的helloworld.xpi文件包,你会发现文件目录的排布如下所示。其中树型结构的叶子部分都是文件,其他的中间结点都是目录。
HelloWorld.xpi
│
│
├─chrome
│ ├─content
│ │ ├─ contents.rdf
│ │ ├─ helloworld-Overlay.xul
│ │ └─ hello.js
│ │
│ ├─locale
│ │ ├─ en-US
│ │ │ ├ contents.rdf
│ │ │ └ helloworld.dtd
│ │ │
│ │ └─ zh-CN
│ │ ├ contents.rdf
│ │ └ helloworld.dtd
│ │
│ │
│ └─skin
│ ├─ qq_small.png
│ ├─ qq_big.png
│ ├─ helloworld.css
│ └─ contents.rdf
│
├─ build.xml
├─ install.rdf
└─ chrome.manifest
通常,Firefox的扩展在根目录中,会有install.rdf文件,这个文件说明了扩展的基本信息,例如扩展的ID、作者、版本等信息。在Firefox1.5之前的版本,该文件还会包含扩展的文件分布信息,在Firefox1.5至后,这些信息都移到了chrome.manifest文件中。在调试的时候,build.xml可以帮助我们自动打包,这个文件对那些在xpi文件中还含有jar文件的扩展特别有用。
根目录下,总是会存在一个chrome目录。chrome下面的格式就不一定了,但是基本都会含有content、locale和skin三个目录。其中,
content目录是用来存放扩展的程序文件和控件格式的资源文件;
locale目录存放不同语言版本,用于扩展的本地化和国际化;
skin目录存放图片等资源文件。
扩展的格式并不一定要拘泥一格,但具体情况需要与install.rdf或chrome.manifest文件中的信息联系。记住,无论如何,良好的习惯总是对你有好处的:请把相应的文件放到它们应该放的地方。
扩展的基本内容
install.rdf
install.rdf是一个扩展的身份证。这么说并不为过,请看下面就是我们helloworld的install.rdf文件:
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
Hello World
{12a1584b-2123-473d-8752-e82e74e3cb11}
0.4
2
A test extension
Marvel
LiuWenmao
http://marvel.hit.edu.cn/
{ec8030f7-c20a-464f-9b0e-13a3a9e97384}
0.9
1.5
可以看得出,这是一个xml格式的文件。根节点为RDF。命名空间为http://www.w3.org/1999/02/22-rdf-syntax-ns# ,前缀为em[4]。下面介绍每一个元素和属性的意义:
Hello World
{12a1584b-2123-473d-8752-e82e74e3cb11}
0.4
2
A test extension
Marvel
LiuWenmao
http://marvel.hit.edu.cn/
em:name:扩展的名字,例如我的名字叫“刘文懋”,而我的扩展叫“Hello World”。J
em:id:扩展的ID号,每一个扩展都会有一个不同的GUID,就如同你的身份证号,用于区分你的扩展与其他人的扩展,所以很明显,全球所有的Firefox插件的ID都不一样。所以,当你写自己的扩展的时候,需要获得一个全球唯一对GUID,Andy Hoskinson帮我们完成了这项工作,你可以登录http://www.hoskinson.net/webservices/guidgeneratorclient.aspx 来获得一个GUID。点击一下Generate GUID按钮,很简单吧,但是这很重要,如果你不想惹麻烦的话!
Firefox1.5支持“User@Location”这种ID的格式。
请注意,当你在“扩展项”中查看扩展信息的时候,你能看到的只有扩展的name,ID你是看不到的,但是Firefox的确是依靠ID来工作的。正如我们在平时总是称呼各自的名字,但是等到登记信息的时候,完全是按照身份证号来区分的。Firefox也是一样的。
em:version:顾名思义,这是扩展的版本号,没什么多说的。
em:type:这是类型。Firefox的插件很强,它支持的不只扩展一种。例如:type=2时表示扩展(Extensions), type=4时表示主题(Themes),type= 8时表示地区(Locale),这和本地化有关,type=16时表示插件(Plugin)。
em:description:扩展的描述,对扩展的简单说明。
em:creator:扩展的创建者。
em:contributor:扩展的贡献者。可以有多个em:contributor,毕竟可以有很多贡献者。
em:homepageURL:扩展的主页。
以上几项,除了ID之外,都会出现在Firefox的“工具”-〉“扩展”项的扩展列表的各项摘要中。
好,让我们到下一部分:
{ec8030f7-c20a-464f-9b0e-13a3a9e97384}
0.9
1.5
em:targetApplication:本扩展可以被使用的应用程序,它的字节点是对这个应用程序的说明,我们的Hello world仅在Firefox下运行,所以只有一个em:targetApplication节点,如果你认为你开发的扩展可以在mozilla的其它应用程序中运行的话,可以在这里多写几个em:targetApplication。
em:id:em:targetApplication的ID号,正如Firefox的扩展有自己的ID号一样,Mozilla的每一个应用程序也都有自己的ID号。例如Firefox、Thunderbird等等,他们都需要有自己的ID号来进行标识。例如,本扩展使用的Firefox的ID号是{ec8030f7-c20a-464f-9b0e-13a3a9e97384}。
em:minVersion:扩展支持的应用程序的最低版本号,举个例子,Firefox1.5有很多的功能是FF1.0.7使用不了的,或者FF1.0.7的一些功能已不被FF1.5支持了,这样的话,每一个扩展都应该有一个Firefox的适用的版本的范围。最大值和最小值的意义也在于此。
em:maxVersion:说明同上,假设这个值为1.0+,那么你会发现Firefox1.5会自动将其禁用,解决方法是你可以将这个值手动改为1.5,前提是这个扩展可以在Firefox1.5下正常运行。
有一些支持Firefox旧版本的扩展还会有下列的东东:
content/
skin/
locale/zh-CN/
locale/zh-TW/
locale/en-US/
这段东西是像Firefox说明了扩展的目录分布。Firefox1.5已经不使用这部分了,对应的,将这部分的内容转移到了chrome.manifest文件中,只有当chrome.manifest文件中没有相应的目录分布的时候,才会回来找。
如Firefox扩展的格式所说,扩展包是由content、skin、locale三部分组成的。这段就说明了这三部分的分布情况,具体的对应内容参见下部分chrome.manifest。
需要注意的是,上面每一个节点中的值都是以“/”结尾的,如果漏掉了这个东西,Firefox就会找不到对应得目录!
理解Chrome[5]
在分析chrome.manifest文件之前,我们必须理解Chrome这个概念。作为Firefox,它的底层是使用了高效并且不能被修改的运行时引擎(runtime engine),在此之上是比较“厚”的可读可修改的解释层。
Chrome代表了Firefox提供的所有用户接口——XUL、CSS、JavaScript、图像、 RDF、文本和HTML文档。RDF和XUL是最重要的文档。
从物理层面上说,Chrome是Firefox数据库中的数据。Firefox需要获得扩展的信息,所以它会在启动的时候,读入RDF文件,完成对扩展的注册,将扩展的信息存放到Firefox的内存数据库中。所以一个扩展只有在Firefox的扩展搜索范围中,并且被Firefox注册了,它才能称为Chrome。
在逻辑层面上说,Chome是一组URL的集合。正如你可以使用http://www.google.com 来访问Google的网页一样,你可以chrome://URL 的方式来访问Chrome的资源。事实上,这是一种映射关系。例如你的电脑中根目录下存放有一个扩展,其中有一个xul文件:/tests/content/package.xul,你可以在浏览器中的地址栏中输入:file:///tests/content/ package.xul ,这样你就可以查看该文件了,但是在Chrome中,如果你已经将conten目录注册了,那么你同样可以在地址栏中输入chrome://test/content/package.xul,这样就可以浏览这个文件了。所以从这个角度来说Chrome可以看作一种Firefox自己定义的协议,不是吗?
说道Chrome,不得不说一下Jar文件。Firefox支持将Chrome的内容全部放在一个zip格式的文件中,这个文件的后缀名为.jar。这个文件可以包括窗口内容、皮肤主题、本地化代码,以及前三个的任意组合。
至于jar文件中内容的引用有所不同。例如有一个/test/hello.jar中还有一个helloworld.xul文件,那么该文件引用地址应该为:
jar:file:///tmp/example.jar!/example.txt。
请注意jar后面有一个感叹号。特别注意的是jar文件的目录分布。
例如正常没有压缩的目录排布为:
test/content/…
test/locale/…
test/skin/…
但是如果要将其压缩为jar文件,那么需要将其重新排列为:
/content/test
/locale /test
/skin /test
这种设计的一个合理解释是Firefox可以在运行的时候更快地搜索该压缩文件。
chrome.manifest
这个文件是Firefox1.5引入的,用于对一些扩展内容、结构的说明和映射。我的Hello World的chrome.manifest文件内如如下:
content helloworld chrome/content/
locale helloworld en-US chrome/locale/en-US/
locale helloworld zh-CN chrome/locale/zh-CN/
skin helloworld classic/1.0 chrome/skin/
overlay chrome://browser/content/browser.xul chrome://helloworld/content/helloworld-Overlay.xul
style chrome://global/content/customizeToolbar.xul chrome://helloworld/skin/helloworld.css
先看前四行:
content helloworld chrome/content/
locale helloworld en-US chrome/locale/en-US/
locale helloworld zh-CN chrome/locale/zh-CN/
skin helloworld classic/1.0 chrome/skin/
根据上一节的叙述,这四行是为了让Firefox在启动的时候,将本地的目录注册到Chrome的数据库中。
我们的Hello world扩展包中包含的内容有content、locale、skin三个部分。其中locale包含了美式英语和简体中文的文件,所以一共有四项。
Content的格式为:
content Name Location
其中,
content:chrome包中的类型,这里为content
Name:chrome包的名字
Location:chrome包文件的位置。注意最后的“/”,别忘了,否则扩展是无法加载的!
所以,第一行的意思就是:一个叫sample的chrome包, 我们可以从位置chrome/content/找到它的content文件。这里的路径是相对于chrome.manifest文件的路径而言的相对路径。
类似的,下面三句定义了locale和skin的位置。
现在,我们已经将本地物理文件与Firefox逻辑上的Chrome的URL建立一个映射,例如:content-〉chrome/content/。我们的扩展有一个content.rdf文件,位置在/chrome/content下,那么我们就可以在浏览器的地址栏中输入 “chrome://helloworld/content/content.rdf”来查看该文件,事实上,Firefox也是按照这个URL来寻找该文件的。
这四行可以与上一节的em:file对照一下,它们在Firefox中实现的功能是一致的。只不过这种写法是Firefox 1.5引入的。假如你的扩展包中没有chrome.manifest而只有install.rdf文件,那么Firefox会解析install.rdf文件,之后,生成一个chrome.manifest文件。
接下来的两行:
overlay chrome://browser/content/browser.xul chrome://helloworld/content/helloworld-Overlay.xul
style chrome://global/content/customizeToolbar.xul chrome://helloworld/skin/helloworld.css
这两行也是向Firefox注册,但这次注册的是你需要重写控件的代码文件(customizeToolbar.xul和helloworld-Overlay.xul)和控件的样式文件(helloworld.css)。Firefox启动的时候会将helloworld-Overlay.xul 合并到browser.xul,从而实现自定义控件的加载。
这几个文件的详细内容我们在接下来的部分进行讨论。
让Firefox说“Hello World”
添加控件接下来,我们需要实现一些基本功能。首先添加一个菜单,用户点击之后,可以弹出一个“Hello World”的窗口。接下来,我们熟悉一下其他的控件,例如状态栏等。
Firefox的控件是由前台的xml格式的文件xul和后台的javascript脚本的js两部分内容组成的。前台的xul文件定义控件的外观和触发事件,后台的js文件实现具体的事件,从而实现了表现和实现的分离。
添加菜单项
首先,我们来实现菜单的菜单项。本例的效果是添加一个菜单项,如下图的“Click Me!”项:
记得上一节我们在chrome.manifest文件中将browser.xul 和helloworld-Overlay.xul注册了吗?我们使用了overlay chrome://browser/content/browser.xul chrome://helloworld/content/helloworld-Overlay.xul,从而Firefox在加载默认浏览器文件browser.xul的同时,会将helloworld-Overlay.xul也加载上去。
所以,我们需要再helloworld-Overlay.xul中加入自己的控件。好了,我写了一个简单的控件menu_Hello:
helloworld-Overlay.xul
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
下面我们来分析一下各个部分。
首先,定义了本文件唯一的ID号为“helloworldOverlay”。
接着,定义了控件触发事件的脚本文件为 chrome://helloworld/content/hello.js。
然后,我们开始定义控件。首先要找到控件的父控件——至少Firefox要知道该把它放在哪里。这里我们找到了“工具”菜单menu_ToolsPopup。至于我们怎么知道“工具”菜单的ID是menu_ToolsPopup的,我推荐使用Firefox自带的开发工具Dom Inspector,至少我是这么知道它的ID的。
找到父控件之后,我们就可以自定义控件了:
这句说明,我们的控件ID为menu_Hello,显示的文本为Click Me!,快捷键为C,位置在“工具”菜单的最上面,点击后触发的事件为onShowMenu()(onShowMenu事件在hello.js中定义,正如我们上面所说的)。
好了,定义完控件的外部属性,我们就需要处理它的触发事件了。打开chrome\content\ hello.js,输入:
function onShowMenu()
{
window.alert("hello");
}
这样我们就完成了菜单项的工作。
如果你现在就像看看效果,那么请转到“部署Firefox扩展”部分;如果你还想看看其他的控件以及样式表的使用,可以继续。
添加工具栏
接下来,我们会添加一个工具栏按钮。从这部分,我们可以知道如何使用工具栏控件,以及如何使用样式。这部分的实际效果如下图:
我们修改一下helloworld-Overlay.xul文件,添加一个叫tbarHello 的toolbarbutton,以及下拉菜单和菜单项。为了简单起见,我去掉了上一节的菜单项的部分:
helloworld-Overlay.xul
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
type="menu-button" label="Test"
oncommand=" onTbarHello();">
下面我们来分析这段代码:
1导入控件样式:
我们需要对下面的控件进行修饰,所以需要引入css样式,这与HTTP的css类似。上面这句说明,我们可能会用到chrome://helloworld/skin/helloworld.css定义的控件样式,事实上的确如此。
2 定义控件
…… 就是定义控件的代码。首先我们找到navigator-toolbox节点,就是Firefox的导航栏。然后在上面添加一个按钮tbarHello,类型为menu-button,,触发事件为onTbarHello()。此外还包括了一个菜单、三个菜单项。具体的说明这里就省略了,你可以使用Dom Inspector来查看各个控件的类型和属性值。
3 定义控件样式
也许你会说,我只看到了你导入了样式文件,但是具体它是怎么使用的呢?或者说控件和它的样式是怎么管联起来的呢?
我们可以来看一看我们导入的CSS文件:
Helloworld.css
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
#tbarHello {
list-style-image: url("chrome://helloworld/skin/qq_big.png");
}
toolbar[iconsize="small"] #tbarHello {
list-style-image: url("chrome://helloworld/skin/qq_small.png");
}
我们可以看到,这个文件定义了一个tbarHello的list-style-image属性[6]。list-style-image的一般语法是:list-style-image: url(…)|none, 这个属性是用来显示特定list-item的图像的,即用后面url中的图像来显示该控件。这里我们使用的是chrome://helloworld/skin/qq_big.png。
但是仅仅有这句还是不够的。Firefox提供了两种图标的显示方法,一种是大图标,另一种是小图标。大图标默认的大小为24x24,小图标默认的大小为16x16。刚才我们定义的图标是大图标,所以我们需要定义小图标,方法为toolbar[iconsize="small"] #tbarHello{}这三行。
这样我们定义了toolbar的显示图像。当然还有其他的属性可以定义,但是这里我们只定义了它的图像。
4 实现控件功能
这部分尽管是最重要的,但是在本例这里不是重点。所以可以用最简单的方式实现xul文件中需要使用的onTbarHello、addName、removeName和showState函数。
我们的hello.js代码如下:
Hello.js
function addName()
{
window.alert("Add name");
}
function removeName()
{
window.alert("Remove name");
}
function showState()
{
window.alert("Show state");
}
function onShowMenu()
{
window.dump("hello");
window.alert("hello");
}
function onTbarHello()
{
window.alert("hello");
}
至此,我们完成了控件的样式的定义和使用。你可以加入更多的样式,完成更复杂的功能,只要你有足够的想象力。
实现本地化[7]
好了,到目前为止,Firefox可以说“Hello World”了。但问题是世界上还有十三亿中国人,那么显然“Hello World”使他们认为Firefox是一个洋玩意儿,它们可能会给Firefox起一个名字叫“洋狐狸”[8]。更糟的是,这十三亿人中很多人只认识中文,不懂得abc,那么只有英文的Firefox不会是他们的选择。
在本节中,我们讲述的是如何在Firefox中实现扩展的本地化。我们需要重写helloworld-Overlay.xul :
helloworld-Overlay.xul
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
注意到和第一个版本有什么不同吗?相信你已经发现了menu_Hello的label已经变成了&btn_Hello.label;,同样的accesskey也变成了这种形式。
如果你学过HTML语法,你可能会想到这可能是转义。例如,在HTML中“<”被转义成为了“<”。
对,这也是一种转义,但是略微不同的是,&btn_Hello.label;和&btn_Hello.accesskey;其实Firefox或者其他的标准都没有定义它们的含义,这是有你自己来决定的。
你需要在你导入的dtd文件中进行说明,本例中,你需要在chrome://helloworld/locale/helloworld.dtd添加相应的定义。
也许到这一步你会问,这个helloworld.dtd文件是哪一个呢?到底是chrome\locale\en-US\ helloworld.dtd 还是 chrome\locale\zh-CN helloworld.dtd呢?
其实,这是由Firefox决定的。如果你的Firefox的locale是en-US,那就是chrome\locale\en-US\ helloworld.dtd,如果你的Firefox的locale是zh-CN,那就是chrome\locale\ zh-CN \ helloworld.dtd。
你需要做的工作就是就是告诉Firefox你的en-US或zh-CN的locale文件夹在什么地方。现在你要在chrome\locale\en-US和chrome\locale\zh-CN下分别建立一个contents.rdf文件。chrome\locale\en-US下的contents.rdf如下:
contents.rdf
-
-
-
-
-
chrome\locale\en-US下的contents.rdf也类似,只不过把所有的zh-CN换成en-US即可。
最后,我们要在相应的locale目录下建立不同locale的helloworld.dtd。还是以英语为例,我们新建chrome\locale\en-US\helloworld.dtd,内容如下:
helloworld.dtd(en-US)
在本例中,当Firefox解析到helloworld-Overlay.xul文件中的“label="&btn_Hello.label;”时,并且locale为en-US,那么它就会到chrome\locale\en-US\helloworld.dtd文件中寻找相应的btn_Hello.label项,即“"Click Me!”。
这样,我们就实现了动态加载控件的label,同样的,我们可以加载tip。
类似的,我们可以填写chrome\locale\zh-CN下的helloworld.dtd文件。假如系统的locale为zh-CN,那么我们的helloworld就会说中文了。
这样,当Firefox每次启动的时候,会根据系统的locale来动态的加载不同的helloworld.dtd。
部署Firefox的扩展
现在Firefox的部署方式一共有两种:
打包部署
这种方式是最普遍的,可以得到Firefox的所有版本的支持。我们可以将完成的扩展目录压缩成zip格式的文件,后缀名为.xpi。
当涉及到扩展中有jar文件的时候,打包过程会比较复杂,因为存在多次压缩的过程。为了简单起见,你可以自己编写一个build.xml, 然后使用ant[9]来组装。下面就是一个文件的样例:
includes="content/**" />
prefix="chrome" />
安装有两种方式,你可以将这个xpi文件上传到Web服务器上,但前提是该服务器能实现application/x-xpinstall功能。另一种方法是在Firefox中选择“文件”-〉“打开文件”,选择该xpi文件即可。
直接部署
Firefox1.5支持这种部署方式。这种方式特别适合调试扩展。
你可以直接到Firefox的扩展的系统目录,一般为“%SYSTEM_DRIVER%:\Documents and Settings\%User%\Application Data\Mozilla\Firefox\Profiles\ default\extensions”。
建立一个文本文件,文件内容为你的扩展的位置。例如我的是“E:\My Documents\Visual Studio Projects\firefox\helloworld\chrome\content”,文件名为扩展的ID号,本例为{12a1584b-2123-473d-8752-e82e74e3cb11}。
保存文件后,重启Firefox即可。
无论用哪种方式,Firefox启动之后,都会加载扩展。你可以到“工具”-〉“扩展项”中查看具体的内容,信息应该与你的install.rdf内容一致。
调试Firefox的扩展
你可以在控制台中对firefox进行调试。Firefox的控制台类似于C语言的控制台,你可以将一些变量的值打印出来,或是可以打印出一些控制的信息,这些信息对你调试firefox的扩展都是十分有用的。
首先,你需要将这个功能打开,在地址栏中输入:about:config , 此时你会发现有很多firefox的配置项,怎么有点像windows的注册表呢?That’s right,这就是Firefox的注册表,你可以在这里放入一些定制的值,实现特定的功能。
我们需要新建一个Boolean类型的配置项 “browser.dom.window.dump.enabled”,它的值为true。
然后,在你的Firefox的快捷方式的属性中,把“目标”项添加一个“-console”,例如我的就改为了"C:\Program Files\Mozilla Firefox\firefox.exe" –console ,这样每次Firefox启动的时候都会出现一个控制台。当然你也可以在命令行中输入上面的命令,但是你应该知道最简单的方式工作的最好,不是吗?
最后,你可以在你的程序中添加window.dump()函数。例如:
window.dump(“Hello world!\n”);
这样,当程序执行到这里的时候,控制台上就会出现“Hello world”的字样了。
获得Hello World的源代码
你可以从以下地址获得本的实验的Hello World代码: http://marvel.hit.edu.cn:8080/text/firefox/helloworld.xpi
贡献Firefox社区
如果你想写自己的Firefox扩展,或者想为Firefox做些东西,可以登录mozilla的开发网站:http://www.mozdev.org/ 。希望你也能成为Firefox的一名开发者。
Contact Me
本人能力有限,一定有地方讲的不正确或是不确切,欢迎来信交流。我的Email是liuwenmao@hit.edu.cn
参考文献
[1] Mozilla Developer Center, Building an Extension, 15 November 2005,http://developer.mozilla.org/en/docs/Building_an_Extension
[2] Brian Duff, Writing an Extension for Firefox , October 02, 2004, http://www.orablogs.com/duffblog/archives/000536.html
[1] Firefox的简称为FF,本文以后涉及到的所有“FF”,如无特别说明,均指Firefox。
[2] 你可以到https://addons.mozilla.org/extensions/moreinfo.php?application=firefox&id=1419 下载该扩展。
[3] JAR 文件就是 Java Archive File,JAR 文件与 ZIP 文件唯一的区别就是在 JAR 文件的内容中,包含了一个 META-INF/MANIFEST.MF 文件,这个文件是在生成 JAR 文件的时候自动创建的。
[4] Xml格式不在本文的讨论范围之内。如果读者想知道xml命名空间的更多内容,请参见 《了解 XML 命名空间》中的“使用命名空间”一节(http://www.chinaitpower.com/A/2004-11-14/140015.html )
[5]参见《Firefox Hacks: Tips & Tools for Next-Generation Web Browsing》 :http://books.google.com/books?hl=en&id=PNEYS39cvRQC&dq=what+is+chrome+firefox&prev=http://www.google.com/search%3Fq%3Dwhat%2Bis%2Bchrome%2Bfirefox%26btnG%3D%25E6%2590%259C%25E7%25B4%25A2%26hl%3Dzh-CN%26newwindow%3D1&pg=PP1&printsec=0&lpg=PP1&sig=oUyWZLI9PC_KsnNAoF6msKBLSbI
[6]参见http://www.htmlhelp.com/reference/css/classification/list-style-image.html 和http://www.w3schools.com/css/pr_list-style-image.asp
[7] 关于国际化和本地化的更多内容参见“开源软件国际化” http://i18n.linux.net.cn/ 和Linux 国际化本地化和中文化 http://www.linuxforum.net/doc/i18n-new.html
[8] 我们家乡话就有很多带“洋”的词,例如“洋火柴”、“洋娃娃”等等。因为当时这些都是从西洋过来的。
[9] Ant可以从http://ant.apache.org/ 免费下载。
刘文懋
Why Firefox?
如果有人问我为什么用Firefox[1],首先毫无疑问的是它代表了开放和自由的精神,其次嘛,我会说是它的可扩展性。
Firefox最激动人心的特点就是它提供了开放的接口,你可以使用这些接口来做各种应用,完成各种各样的功能。你应该不曾给IE添点什么吧,微软不见得这么大方能告诉你什么有用的东西。他最慷慨的事就是给你一个COM组件,记得我对IE的最高级的应用,就是在一次网络大作业中,把整个IE嵌在我的程序里,仅此而已。而Firefox则不同了,当你看到了Fireftp就知道我在说什么了。
请合上你的下巴,这没有什么值得惊讶的。这就是Firefox,中间那个cool的ftp工具只是它的一个扩展(Extesion)而已。
想做一个这样的东东吗?我不会告诉你到底有多难,因为这不是我开发的,有兴趣的话你可以自己试一试,网址是http://fireftp.mozdev.org/ 。
类似的扩展还有很多,你可以到mozilla的扩展库去看看,据官方统计,到2005年11月9日,(忘了告诉你了,2004年11月9日是Firefox的诞生日,也就是说它还只是一个小baby),用户至少可以使用700个扩展(Extension)或者附件(Add-on)。可见Firefox的扩展发展是多么的迅速!
以前我在99%的时间内使用Firefox,另外1%的时间使用IE浏览一些不遵从W3C标准而非用IE不可的垃圾网站,我们学校的BBS很不幸地成为其中一员。但是现在我在100%的时间内使用Firefox,这归功于一个ie tab[2]的Firefox扩展。所幸随着网络标准的日渐被重视,Firefox有可能会支持所有的网站。 :)
好了,说了这么多Firefox扩展的好处,是不是有点心动了呢?那么就用一个Hello World来开始我们的第一个Firefox扩展吧。别说我太不in了,毕竟hello world总是最容易让我们使所有编程语言的开场白,不是吗?
Here we go!
认识Firefox的扩展
Firefox扩展的功能
从功能来说,Firefox扩展应该是用户和浏览器内核交互的一种体系结构。扩展可以满足用户一些特定的需要,实现特定的功能。开发者可以使用内核提供的一些用户接口,编写自己的实现代码,完成自己设想的功能。
Firefox扩展的格式
从开发的角度来讲,Firefox的扩展是一个文件目录的集合,它们按照一定格式和规范编写和排布的。最终,发布给用户的是一个xpi包。别感到奇怪,这个xpi文件和那些jar[3]的文件一样,都是zip格式的压缩文件。所以这下你懂了吧,把你做完的文件按照zip格式压缩一下就成了我们的扩展包了。
那么究竟具体的xpi文件中是什么情景的?解开我提供的helloworld.xpi文件包,你会发现文件目录的排布如下所示。其中树型结构的叶子部分都是文件,其他的中间结点都是目录。
HelloWorld.xpi
│
│
├─chrome
│ ├─content
│ │ ├─ contents.rdf
│ │ ├─ helloworld-Overlay.xul
│ │ └─ hello.js
│ │
│ ├─locale
│ │ ├─ en-US
│ │ │ ├ contents.rdf
│ │ │ └ helloworld.dtd
│ │ │
│ │ └─ zh-CN
│ │ ├ contents.rdf
│ │ └ helloworld.dtd
│ │
│ │
│ └─skin
│ ├─ qq_small.png
│ ├─ qq_big.png
│ ├─ helloworld.css
│ └─ contents.rdf
│
├─ build.xml
├─ install.rdf
└─ chrome.manifest
通常,Firefox的扩展在根目录中,会有install.rdf文件,这个文件说明了扩展的基本信息,例如扩展的ID、作者、版本等信息。在Firefox1.5之前的版本,该文件还会包含扩展的文件分布信息,在Firefox1.5至后,这些信息都移到了chrome.manifest文件中。在调试的时候,build.xml可以帮助我们自动打包,这个文件对那些在xpi文件中还含有jar文件的扩展特别有用。
根目录下,总是会存在一个chrome目录。chrome下面的格式就不一定了,但是基本都会含有content、locale和skin三个目录。其中,
content目录是用来存放扩展的程序文件和控件格式的资源文件;
locale目录存放不同语言版本,用于扩展的本地化和国际化;
skin目录存放图片等资源文件。
扩展的格式并不一定要拘泥一格,但具体情况需要与install.rdf或chrome.manifest文件中的信息联系。记住,无论如何,良好的习惯总是对你有好处的:请把相应的文件放到它们应该放的地方。
扩展的基本内容
install.rdf
install.rdf是一个扩展的身份证。这么说并不为过,请看下面就是我们helloworld的install.rdf文件:
可以看得出,这是一个xml格式的文件。根节点为RDF。命名空间为http://www.w3.org/1999/02/22-rdf-syntax-ns# ,前缀为em[4]。下面介绍每一个元素和属性的意义:
em:name:扩展的名字,例如我的名字叫“刘文懋”,而我的扩展叫“Hello World”。J
em:id:扩展的ID号,每一个扩展都会有一个不同的GUID,就如同你的身份证号,用于区分你的扩展与其他人的扩展,所以很明显,全球所有的Firefox插件的ID都不一样。所以,当你写自己的扩展的时候,需要获得一个全球唯一对GUID,Andy Hoskinson帮我们完成了这项工作,你可以登录http://www.hoskinson.net/webservices/guidgeneratorclient.aspx 来获得一个GUID。点击一下Generate GUID按钮,很简单吧,但是这很重要,如果你不想惹麻烦的话!
Firefox1.5支持“User@Location”这种ID的格式。
请注意,当你在“扩展项”中查看扩展信息的时候,你能看到的只有扩展的name,ID你是看不到的,但是Firefox的确是依靠ID来工作的。正如我们在平时总是称呼各自的名字,但是等到登记信息的时候,完全是按照身份证号来区分的。Firefox也是一样的。
em:version:顾名思义,这是扩展的版本号,没什么多说的。
em:type:这是类型。Firefox的插件很强,它支持的不只扩展一种。例如:type=2时表示扩展(Extensions), type=4时表示主题(Themes),type= 8时表示地区(Locale),这和本地化有关,type=16时表示插件(Plugin)。
em:description:扩展的描述,对扩展的简单说明。
em:creator:扩展的创建者。
em:contributor:扩展的贡献者。可以有多个em:contributor,毕竟可以有很多贡献者。
em:homepageURL:扩展的主页。
以上几项,除了ID之外,都会出现在Firefox的“工具”-〉“扩展”项的扩展列表的各项摘要中。
好,让我们到下一部分:
em:targetApplication:本扩展可以被使用的应用程序,它的字节点是对这个应用程序的说明,我们的Hello world仅在Firefox下运行,所以只有一个em:targetApplication节点,如果你认为你开发的扩展可以在mozilla的其它应用程序中运行的话,可以在这里多写几个em:targetApplication。
em:id:em:targetApplication的ID号,正如Firefox的扩展有自己的ID号一样,Mozilla的每一个应用程序也都有自己的ID号。例如Firefox、Thunderbird等等,他们都需要有自己的ID号来进行标识。例如,本扩展使用的Firefox的ID号是{ec8030f7-c20a-464f-9b0e-13a3a9e97384}。
em:minVersion:扩展支持的应用程序的最低版本号,举个例子,Firefox1.5有很多的功能是FF1.0.7使用不了的,或者FF1.0.7的一些功能已不被FF1.5支持了,这样的话,每一个扩展都应该有一个Firefox的适用的版本的范围。最大值和最小值的意义也在于此。
em:maxVersion:说明同上,假设这个值为1.0+,那么你会发现Firefox1.5会自动将其禁用,解决方法是你可以将这个值手动改为1.5,前提是这个扩展可以在Firefox1.5下正常运行。
有一些支持Firefox旧版本的扩展还会有下列的东东:
这段东西是像Firefox说明了扩展的目录分布。Firefox1.5已经不使用这部分了,对应的,将这部分的内容转移到了chrome.manifest文件中,只有当chrome.manifest文件中没有相应的目录分布的时候,才会回来找。
如Firefox扩展的格式所说,扩展包是由content、skin、locale三部分组成的。这段就说明了这三部分的分布情况,具体的对应内容参见下部分chrome.manifest。
需要注意的是,上面每一个节点中的值都是以“/”结尾的,如果漏掉了这个东西,Firefox就会找不到对应得目录!
理解Chrome[5]
在分析chrome.manifest文件之前,我们必须理解Chrome这个概念。作为Firefox,它的底层是使用了高效并且不能被修改的运行时引擎(runtime engine),在此之上是比较“厚”的可读可修改的解释层。
Chrome代表了Firefox提供的所有用户接口——XUL、CSS、JavaScript、图像、 RDF、文本和HTML文档。RDF和XUL是最重要的文档。
从物理层面上说,Chrome是Firefox数据库中的数据。Firefox需要获得扩展的信息,所以它会在启动的时候,读入RDF文件,完成对扩展的注册,将扩展的信息存放到Firefox的内存数据库中。所以一个扩展只有在Firefox的扩展搜索范围中,并且被Firefox注册了,它才能称为Chrome。
在逻辑层面上说,Chome是一组URL的集合。正如你可以使用http://www.google.com 来访问Google的网页一样,你可以chrome://URL 的方式来访问Chrome的资源。事实上,这是一种映射关系。例如你的电脑中根目录下存放有一个扩展,其中有一个xul文件:/tests/content/package.xul,你可以在浏览器中的地址栏中输入:file:///tests/content/ package.xul ,这样你就可以查看该文件了,但是在Chrome中,如果你已经将conten目录注册了,那么你同样可以在地址栏中输入chrome://test/content/package.xul,这样就可以浏览这个文件了。所以从这个角度来说Chrome可以看作一种Firefox自己定义的协议,不是吗?
说道Chrome,不得不说一下Jar文件。Firefox支持将Chrome的内容全部放在一个zip格式的文件中,这个文件的后缀名为.jar。这个文件可以包括窗口内容、皮肤主题、本地化代码,以及前三个的任意组合。
至于jar文件中内容的引用有所不同。例如有一个/test/hello.jar中还有一个helloworld.xul文件,那么该文件引用地址应该为:
jar:file:///tmp/example.jar!/example.txt。
请注意jar后面有一个感叹号。特别注意的是jar文件的目录分布。
例如正常没有压缩的目录排布为:
test/content/…
test/locale/…
test/skin/…
但是如果要将其压缩为jar文件,那么需要将其重新排列为:
/content/test
/locale /test
/skin /test
这种设计的一个合理解释是Firefox可以在运行的时候更快地搜索该压缩文件。
chrome.manifest
这个文件是Firefox1.5引入的,用于对一些扩展内容、结构的说明和映射。我的Hello World的chrome.manifest文件内如如下:
content helloworld chrome/content/
locale helloworld en-US chrome/locale/en-US/
locale helloworld zh-CN chrome/locale/zh-CN/
skin helloworld classic/1.0 chrome/skin/
overlay chrome://browser/content/browser.xul chrome://helloworld/content/helloworld-Overlay.xul
style chrome://global/content/customizeToolbar.xul chrome://helloworld/skin/helloworld.css
先看前四行:
content helloworld chrome/content/
locale helloworld en-US chrome/locale/en-US/
locale helloworld zh-CN chrome/locale/zh-CN/
skin helloworld classic/1.0 chrome/skin/
根据上一节的叙述,这四行是为了让Firefox在启动的时候,将本地的目录注册到Chrome的数据库中。
我们的Hello world扩展包中包含的内容有content、locale、skin三个部分。其中locale包含了美式英语和简体中文的文件,所以一共有四项。
Content的格式为:
content Name Location
其中,
content:chrome包中的类型,这里为content
Name:chrome包的名字
Location:chrome包文件的位置。注意最后的“/”,别忘了,否则扩展是无法加载的!
所以,第一行的意思就是:一个叫sample的chrome包, 我们可以从位置chrome/content/找到它的content文件。这里的路径是相对于chrome.manifest文件的路径而言的相对路径。
类似的,下面三句定义了locale和skin的位置。
现在,我们已经将本地物理文件与Firefox逻辑上的Chrome的URL建立一个映射,例如:content-〉chrome/content/。我们的扩展有一个content.rdf文件,位置在/chrome/content下,那么我们就可以在浏览器的地址栏中输入 “chrome://helloworld/content/content.rdf”来查看该文件,事实上,Firefox也是按照这个URL来寻找该文件的。
这四行可以与上一节的em:file对照一下,它们在Firefox中实现的功能是一致的。只不过这种写法是Firefox 1.5引入的。假如你的扩展包中没有chrome.manifest而只有install.rdf文件,那么Firefox会解析install.rdf文件,之后,生成一个chrome.manifest文件。
接下来的两行:
overlay chrome://browser/content/browser.xul chrome://helloworld/content/helloworld-Overlay.xul
style chrome://global/content/customizeToolbar.xul chrome://helloworld/skin/helloworld.css
这两行也是向Firefox注册,但这次注册的是你需要重写控件的代码文件(customizeToolbar.xul和helloworld-Overlay.xul)和控件的样式文件(helloworld.css)。Firefox启动的时候会将helloworld-Overlay.xul 合并到browser.xul,从而实现自定义控件的加载。
这几个文件的详细内容我们在接下来的部分进行讨论。
让Firefox说“Hello World”
添加控件接下来,我们需要实现一些基本功能。首先添加一个菜单,用户点击之后,可以弹出一个“Hello World”的窗口。接下来,我们熟悉一下其他的控件,例如状态栏等。
Firefox的控件是由前台的xml格式的文件xul和后台的javascript脚本的js两部分内容组成的。前台的xul文件定义控件的外观和触发事件,后台的js文件实现具体的事件,从而实现了表现和实现的分离。
添加菜单项
首先,我们来实现菜单的菜单项。本例的效果是添加一个菜单项,如下图的“Click Me!”项:
记得上一节我们在chrome.manifest文件中将browser.xul 和helloworld-Overlay.xul注册了吗?我们使用了overlay chrome://browser/content/browser.xul chrome://helloworld/content/helloworld-Overlay.xul,从而Firefox在加载默认浏览器文件browser.xul的同时,会将helloworld-Overlay.xul也加载上去。
所以,我们需要再helloworld-Overlay.xul中加入自己的控件。好了,我写了一个简单的控件menu_Hello:
helloworld-Overlay.xul
下面我们来分析一下各个部分。
首先,定义了本文件唯一的ID号为“helloworldOverlay”。
接着,定义了控件触发事件的脚本文件为 chrome://helloworld/content/hello.js。
然后,我们开始定义控件。首先要找到控件的父控件——至少Firefox要知道该把它放在哪里。这里我们找到了“工具”菜单menu_ToolsPopup。至于我们怎么知道“工具”菜单的ID是menu_ToolsPopup的,我推荐使用Firefox自带的开发工具Dom Inspector,至少我是这么知道它的ID的。
找到父控件之后,我们就可以自定义控件了:
这句说明,我们的控件ID为menu_Hello,显示的文本为Click Me!,快捷键为C,位置在“工具”菜单的最上面,点击后触发的事件为onShowMenu()(onShowMenu事件在hello.js中定义,正如我们上面所说的)。
好了,定义完控件的外部属性,我们就需要处理它的触发事件了。打开chrome\content\ hello.js,输入:
function onShowMenu()
{
window.alert("hello");
}
这样我们就完成了菜单项的工作。
如果你现在就像看看效果,那么请转到“部署Firefox扩展”部分;如果你还想看看其他的控件以及样式表的使用,可以继续。
添加工具栏
接下来,我们会添加一个工具栏按钮。从这部分,我们可以知道如何使用工具栏控件,以及如何使用样式。这部分的实际效果如下图:
我们修改一下helloworld-Overlay.xul文件,添加一个叫tbarHello 的toolbarbutton,以及下拉菜单和菜单项。为了简单起见,我去掉了上一节的菜单项的部分:
helloworld-Overlay.xul
oncommand=" onTbarHello();">
下面我们来分析这段代码:
1导入控件样式:
我们需要对下面的控件进行修饰,所以需要引入css样式,这与HTTP的css类似。上面这句说明,我们可能会用到chrome://helloworld/skin/helloworld.css定义的控件样式,事实上的确如此。
2 定义控件
3 定义控件样式
也许你会说,我只看到了你导入了样式文件,但是具体它是怎么使用的呢?或者说控件和它的样式是怎么管联起来的呢?
我们可以来看一看我们导入的CSS文件:
Helloworld.css
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
#tbarHello {
list-style-image: url("chrome://helloworld/skin/qq_big.png");
}
toolbar[iconsize="small"] #tbarHello {
list-style-image: url("chrome://helloworld/skin/qq_small.png");
}
我们可以看到,这个文件定义了一个tbarHello的list-style-image属性[6]。list-style-image的一般语法是:list-style-image: url(…)|none, 这个属性是用来显示特定list-item的图像的,即用后面url中的图像来显示该控件。这里我们使用的是chrome://helloworld/skin/qq_big.png。
但是仅仅有这句还是不够的。Firefox提供了两种图标的显示方法,一种是大图标,另一种是小图标。大图标默认的大小为24x24,小图标默认的大小为16x16。刚才我们定义的图标是大图标,所以我们需要定义小图标,方法为toolbar[iconsize="small"] #tbarHello{}这三行。
这样我们定义了toolbar的显示图像。当然还有其他的属性可以定义,但是这里我们只定义了它的图像。
4 实现控件功能
这部分尽管是最重要的,但是在本例这里不是重点。所以可以用最简单的方式实现xul文件中需要使用的onTbarHello、addName、removeName和showState函数。
我们的hello.js代码如下:
Hello.js
function addName()
{
window.alert("Add name");
}
function removeName()
{
window.alert("Remove name");
}
function showState()
{
window.alert("Show state");
}
function onShowMenu()
{
window.dump("hello");
window.alert("hello");
}
function onTbarHello()
{
window.alert("hello");
}
至此,我们完成了控件的样式的定义和使用。你可以加入更多的样式,完成更复杂的功能,只要你有足够的想象力。
实现本地化[7]
好了,到目前为止,Firefox可以说“Hello World”了。但问题是世界上还有十三亿中国人,那么显然“Hello World”使他们认为Firefox是一个洋玩意儿,它们可能会给Firefox起一个名字叫“洋狐狸”[8]。更糟的是,这十三亿人中很多人只认识中文,不懂得abc,那么只有英文的Firefox不会是他们的选择。
在本节中,我们讲述的是如何在Firefox中实现扩展的本地化。我们需要重写helloworld-Overlay.xul :
helloworld-Overlay.xul
注意到和第一个版本有什么不同吗?相信你已经发现了menu_Hello的label已经变成了&btn_Hello.label;,同样的accesskey也变成了这种形式。
如果你学过HTML语法,你可能会想到这可能是转义。例如,在HTML中“<”被转义成为了“<”。
对,这也是一种转义,但是略微不同的是,&btn_Hello.label;和&btn_Hello.accesskey;其实Firefox或者其他的标准都没有定义它们的含义,这是有你自己来决定的。
你需要在你导入的dtd文件中进行说明,本例中,你需要在chrome://helloworld/locale/helloworld.dtd添加相应的定义。
也许到这一步你会问,这个helloworld.dtd文件是哪一个呢?到底是chrome\locale\en-US\ helloworld.dtd 还是 chrome\locale\zh-CN helloworld.dtd呢?
其实,这是由Firefox决定的。如果你的Firefox的locale是en-US,那就是chrome\locale\en-US\ helloworld.dtd,如果你的Firefox的locale是zh-CN,那就是chrome\locale\ zh-CN \ helloworld.dtd。
你需要做的工作就是就是告诉Firefox你的en-US或zh-CN的locale文件夹在什么地方。现在你要在chrome\locale\en-US和chrome\locale\zh-CN下分别建立一个contents.rdf文件。chrome\locale\en-US下的contents.rdf如下:
contents.rdf
-
-
-
-
-
chrome\locale\en-US下的contents.rdf也类似,只不过把所有的zh-CN换成en-US即可。
最后,我们要在相应的locale目录下建立不同locale的helloworld.dtd。还是以英语为例,我们新建chrome\locale\en-US\helloworld.dtd,内容如下:
helloworld.dtd(en-US)
在本例中,当Firefox解析到helloworld-Overlay.xul文件中的“label="&btn_Hello.label;”时,并且locale为en-US,那么它就会到chrome\locale\en-US\helloworld.dtd文件中寻找相应的btn_Hello.label项,即“"Click Me!”。
这样,我们就实现了动态加载控件的label,同样的,我们可以加载tip。
类似的,我们可以填写chrome\locale\zh-CN下的helloworld.dtd文件。假如系统的locale为zh-CN,那么我们的helloworld就会说中文了。
这样,当Firefox每次启动的时候,会根据系统的locale来动态的加载不同的helloworld.dtd。
部署Firefox的扩展
现在Firefox的部署方式一共有两种:
打包部署
这种方式是最普遍的,可以得到Firefox的所有版本的支持。我们可以将完成的扩展目录压缩成zip格式的文件,后缀名为.xpi。
当涉及到扩展中有jar文件的时候,打包过程会比较复杂,因为存在多次压缩的过程。为了简单起见,你可以自己编写一个build.xml, 然后使用ant[9]来组装。下面就是一个文件的样例:
安装有两种方式,你可以将这个xpi文件上传到Web服务器上,但前提是该服务器能实现application/x-xpinstall功能。另一种方法是在Firefox中选择“文件”-〉“打开文件”,选择该xpi文件即可。
直接部署
Firefox1.5支持这种部署方式。这种方式特别适合调试扩展。
你可以直接到Firefox的扩展的系统目录,一般为“%SYSTEM_DRIVER%:\Documents and Settings\%User%\Application Data\Mozilla\Firefox\Profiles\ default\extensions”。
建立一个文本文件,文件内容为你的扩展的位置。例如我的是“E:\My Documents\Visual Studio Projects\firefox\helloworld\chrome\content”,文件名为扩展的ID号,本例为{12a1584b-2123-473d-8752-e82e74e3cb11}。
保存文件后,重启Firefox即可。
无论用哪种方式,Firefox启动之后,都会加载扩展。你可以到“工具”-〉“扩展项”中查看具体的内容,信息应该与你的install.rdf内容一致。
调试Firefox的扩展
你可以在控制台中对firefox进行调试。Firefox的控制台类似于C语言的控制台,你可以将一些变量的值打印出来,或是可以打印出一些控制的信息,这些信息对你调试firefox的扩展都是十分有用的。
首先,你需要将这个功能打开,在地址栏中输入:about:config , 此时你会发现有很多firefox的配置项,怎么有点像windows的注册表呢?That’s right,这就是Firefox的注册表,你可以在这里放入一些定制的值,实现特定的功能。
我们需要新建一个Boolean类型的配置项 “browser.dom.window.dump.enabled”,它的值为true。
然后,在你的Firefox的快捷方式的属性中,把“目标”项添加一个“-console”,例如我的就改为了"C:\Program Files\Mozilla Firefox\firefox.exe" –console ,这样每次Firefox启动的时候都会出现一个控制台。当然你也可以在命令行中输入上面的命令,但是你应该知道最简单的方式工作的最好,不是吗?
最后,你可以在你的程序中添加window.dump()函数。例如:
window.dump(“Hello world!\n”);
这样,当程序执行到这里的时候,控制台上就会出现“Hello world”的字样了。
获得Hello World的源代码
你可以从以下地址获得本的实验的Hello World代码: http://marvel.hit.edu.cn:8080/text/firefox/helloworld.xpi
贡献Firefox社区
如果你想写自己的Firefox扩展,或者想为Firefox做些东西,可以登录mozilla的开发网站:http://www.mozdev.org/ 。希望你也能成为Firefox的一名开发者。
Contact Me
本人能力有限,一定有地方讲的不正确或是不确切,欢迎来信交流。我的Email是liuwenmao@hit.edu.cn
参考文献
[1] Mozilla Developer Center, Building an Extension, 15 November 2005,http://developer.mozilla.org/en/docs/Building_an_Extension
[2] Brian Duff, Writing an Extension for Firefox , October 02, 2004, http://www.orablogs.com/duffblog/archives/000536.html
[1] Firefox的简称为FF,本文以后涉及到的所有“FF”,如无特别说明,均指Firefox。
[2] 你可以到https://addons.mozilla.org/extensions/moreinfo.php?application=firefox&id=1419 下载该扩展。
[3] JAR 文件就是 Java Archive File,JAR 文件与 ZIP 文件唯一的区别就是在 JAR 文件的内容中,包含了一个 META-INF/MANIFEST.MF 文件,这个文件是在生成 JAR 文件的时候自动创建的。
[4] Xml格式不在本文的讨论范围之内。如果读者想知道xml命名空间的更多内容,请参见 《了解 XML 命名空间》中的“使用命名空间”一节(http://www.chinaitpower.com/A/2004-11-14/140015.html )
[5]参见《Firefox Hacks: Tips & Tools for Next-Generation Web Browsing》 :http://books.google.com/books?hl=en&id=PNEYS39cvRQC&dq=what+is+chrome+firefox&prev=http://www.google.com/search%3Fq%3Dwhat%2Bis%2Bchrome%2Bfirefox%26btnG%3D%25E6%2590%259C%25E7%25B4%25A2%26hl%3Dzh-CN%26newwindow%3D1&pg=PP1&printsec=0&lpg=PP1&sig=oUyWZLI9PC_KsnNAoF6msKBLSbI
[6]参见http://www.htmlhelp.com/reference/css/classification/list-style-image.html 和http://www.w3schools.com/css/pr_list-style-image.asp
[7] 关于国际化和本地化的更多内容参见“开源软件国际化” http://i18n.linux.net.cn/ 和Linux 国际化本地化和中文化 http://www.linuxforum.net/doc/i18n-new.html
[8] 我们家乡话就有很多带“洋”的词,例如“洋火柴”、“洋娃娃”等等。因为当时这些都是从西洋过来的。
[9] Ant可以从http://ant.apache.org/ 免费下载。
Hello World
Hello World
Hello, World Page!
hello world, ruby
"Hello World" for RRDtool
VB.Net编程入门之Hello World
http,session,cookie分析 | Hello World!
常用RGB颜色表--Hello world!
Native C++ "Hello World" working in emulator
DWR的学习文档(Hello World,类型转换,Spring,Annotation)
在地表上秀出Hello, World!虽然有点麻烦...
JBPM 2 (Hello World) - 闲人茶馆 - JavaEye技术网站
DWR的学习文档(Hello World,类型转换,Spring,Annotation)
Hello World by Microsoft Speech SDK 5.1 - Vis...
JBPM 2 (Hello World) - 闲人茶馆 - JavaEye技术网站
二次开发之Hello World! - 二次开发和插件 - WPS Office官方论坛 ...
内部资金转移定价 FTP - Hello World :-) - CSDN博客
"Hello World" for RRDtool - 雨中怡然 - CSDNBlog
hello world: websphere portal v5 最简单的 portlet:第 1 部分,创建和部署
jBPM学习(六)----Hello World JBPM @net -JavaEye技术社区
hello world: websphere portal v5 最简单的 portlet:第 1 部分,创建和部署
[转] 我的第一個PSP程式: Hello World! PSP編程從這里開始!
Mac OS iphone 开发起步 初级教程 hello world (转) - 王超 ...
【易富国际】 - 给新入门CICS的朋友们----CICS下的Hello World! (本站长又一倾力之作)