【zz】firefox扩展开发实例入门之comic扩展

http://bbs.sjtu.edu.cn/bbstcon?board=GNULinux&reid=1234626263
如何写firefox的扩展(注意,这里是extension,
和plugin还是有一定区别的)。这次的实例选的是看comic的插件。虽然若干年前的前辈
门为了让在linux下也能享受到comic已经写好了相当不错的extension,大家可以直接拿
来用。不过因为暂时没想到有什么比较简单的插件(HelloWorld除外)可以作为入门教
程,并同时让大家练练手的,就只有拿这个开刀了~还是希望能有人对这个有兴趣,有朝
一日弄出个我们SJTUer自己的Firefox版本来~废话到此为止,下面进入正题!

一. 基础知识

最直接了当的入门请猛击这里:https://developer.mozilla.org/en/Extensions

当然,如果这篇文章我什么也不介绍,肯定会被人诅咒的。于是,我就稍微说几句
来实现脱盲。

首先,我们要知道,extension,扩展,顾名思义就是给firefox添加新功能的。比
如对于我们亲爱的comic.sjtu.edu.cn,“裸体”状态下的firefox中浏览点击播放图标
,我们的小萌狐狸是不会理你的,这时候,就需要给她弄点extension来调教调教,教教
她如何service。调教步骤如下:
1.从网上找一个扩展,或者自己写一个;
2.给小萌狐穿上这个扩展;
3.“X掉,再打开”。这时候就已经调教完毕可以正常服务了。

本文是教你如何写扩展,我们就要了解一下firefox扩展的文件格式。从网上下载下
来的都是个xpi后缀名的包,其实也就是个zip格式的包改了个名字而已。把这个包拖到f
irefox上就能进行安装。具体这个压缩包有些什么,我将在下一节和实例一起介绍~

最后,说说想在小狐狸身上打主意都需要些什么要求:
1.一定要是怪叔叔,例如sudo;
2.会用电脑,要装有firefox(连情人都没有,怎么能过情人节~);
3.懂英语,很可惜,这是只洋loli;
4.(最好)看的懂HTML,JAVASCRIPT,XML。以上。

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

二. 开发一个comic扩展

这里,不会系统的教你如何去开发一个firefox的扩展,我没那本事。我只能以一个
看comic的小扩展作为例子,让你理解下firefox的扩展。至于能理解到什么程度,看你
造化了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
的所以简化了很多内容,比如字符集处理等。
整个开发的文件目录结构如下:
Comic: ------总目录
-----install.rdf ------扩展安装信息文件
-----chrome.manifest ------chrome目录描述文件
-----chrome: ------chrome目录下是用户界面元素
----------content: ------content目录下是扩展的源代码
---------------overlay.js ------处理脚本
---------------overlay.xul ------用户界面配置
---------------options.xul ------扩展选项配置
你看,其实整个下来也就5个文件,代码也很少,都很容易理解。下面我们就开始逐
个的看看这些文件的代码,和作用。
首先是install.rdf文件:
<?xml version="1.0"?>
&lt;RDF:RDF xmlns:em="<a href="http://www.mozilla.org/2004/em-rdf#" target="_blank">http://www.mozilla.org/2004/em-rdf#</a>
xmlns:NC="<a href="http://home.netscape.com/NC-rdf#" target="_blank">http://home.netscape.com/NC-rdf#</a>
xmlns:RDF="<a href="http://www.w3.org/1999/02/22-rdf-syntax-ns#%3E" target="_blank">http://www.w3.org/1999/02/22-rdf-syntax-ns#&gt;</a>
&lt;RDF:Description RDF:about="urn:mozilla:install-manifest"
em:id="comic@sudo"
em:name="Comic Extension"
em:version="0.1"
em:creator="sudo"
em:description="A simple extension to view movies on
comic.sjtu.edu.cn"
em:optionsURL="chrome://comic/content/options.xul"&gt;
&lt;em:targetApplication RDF:resource="rdf:#$Jw9Pt1"/&gt;
&lt;/RDF:Description&gt;
&lt;RDF:Description RDF:about="rdf:#$Jw9Pt1"
em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
em:minVersion="1.5"
em:maxVersion="3.*" /&gt;
&lt;/RDF:RDF&gt;
这个文件只是用来描述你开发的扩展的,比如说,em:id元素是你扩展的id,应该取
一个唯一的名字,比如可以用你的邮件之类的来命名。em:targetApplication中表示这
个扩展运用的mozilla应用是什么,以为mozilla除了firefox,还有thunderbird等一大
堆东西。
这里em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"是firefox,下面的是版本
号。有些同学的firefox升级后部分插件扩展不能使用了,就是从这里检查出来的。多数
情况下只要修改一下最高版本号,死了的插件和扩展就又能原地复活了。再下面是插件
的描述,是安装后最终显示在附加组件中的信息。这个太简单了,我就不废话了:)
然后是chrome.manifest文件:
content comic chrome/content/
overlay chrome://browser/content/browser.xul
chrome://comic/content/overlay.xul
就两行,不用解释也看的出是干啥的~定义用户界面的内容的位置
再看overlay.xul:
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;overlay id="comic-overlay"
xmlns="<a href="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul%3E" target="_blank">http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul&gt;</a>
&lt;script src="chrome://comic/content/overlay.js"/&gt;
&lt;popup id="contentAreaContextMenu"&gt;
&lt;menuitem id="play-comic" label="Play Online"
oncommand="comic.play()"
insertbefore="context-openlink"/&gt;
&lt;/popup&gt;
&lt;/overlay&gt;
这里定义的是在浏览器中的显示方式,
&lt;script src="chrome://comic/content/overlay.js"/&gt;指出我们要用到这个脚本
来处理。
&lt;popup id="contentAreaContextMenu"&gt;说明这里是一个弹出的菜单,contentArea
ContextMenu是我给这个菜单制定的ID,你想取啥随便你:)
&lt;menuitem id="play-comic" label="Play Online" oncommand="comic.play()"
insertbefore="context-openlink"
image="chrome://comic/content/comic.png"/&gt;
指定了菜单中选项的一些属性,比如标签是Play Online,点击后执行的动作是comi
c.play(),这个是在overlay.js中的,下面会讲到。这里还可以指定位置,insertbefor
e是在哪个item之前插入这个选项。
然后就是options.xul了,这个是配置扩展的地方,代码如下:
&lt;?xml version="1.0"?&gt;
&lt;?xml-stylesheet href="chrome://global/skin/" type="text/css"?&gt;
&lt;prefwindow id="comic-prefs" title="Comic Setting"
xmlns="<a href="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul%3E" target="_blank">http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul&gt;</a>
&lt;prefpane id="perf-setting"&gt;
&lt;preferences&gt;
&lt;preference id="mplayer" name="sjtu.comic.mplayer" type="string"/&gt;
&lt;/preferences&gt;
&lt;vbox&gt;
&lt;label value="mplayer location: "/&gt;
&lt;textbox preference="mplayer"/&gt;
&lt;/vbox&gt;
&lt;/prefpane&gt;
&lt;/prefwindow&gt;
很简单,我们把mplayer播放器的位置保存在firefox的配置之中,配置的位置为sjt
u.comic.mplayer。这个是可以在浏览器中用about:config打开查的到的~然后就是些简
单的配置界面上的东西,我就不啰嗦了:)
最后,最核心的代码当然要javascript上场了,请看overlay.js:直接在代码上注
释了,大家睁大眼睛了!
var comic = {
onLoad: function() {
this.initialized = true;
document.getElementById("contentAreaContextMenu")
.addEventListener("popupshowing",this.showContextMenu,false);
},
//这是加载时做的事,第二条是加入处理菜单时候显示的监听器
getURL:function(){
var URL;
if (gContextMenu &amp;&amp; gContextMenu.link
&amp;&amp; gContextMenu.link.getAttribute("onclick")) {
var result = gContextMenu.link.getAttribute("onclick")
.match(/TruevodPlayEx('(.*)','(.*)','(.*)');/i);
if (result &amp;&amp; result[1] &amp;&amp; result[2]) {
URL = "vod://"+result[1]+"/"+result[2];
URL=URL.replace(/\\/ig, '/');
URL=URL.replace(/\/ig, '');
URL = encodeURI(URL);
URL = unescape(URL);
return URL;
}
}
},
//这个函数是解析页面上的vod的地址,用到正则表达式大家自己去分析分析:)
//这里要注意的是,我把URL转成unicode了,在linux下是能很好的工作的
//但在windows下,由于字符集的问题,碰到非拉丁的玩意就不行了~
//要打补丁的话~有点麻烦,这里就从简了呵呵~

showContextMenu: function() {
document.getElementById(“play-comic”).hidden = true;

if (comic.getURL()) {
document.getElementById(“play-comic”).hidden = false;
}
},
//这个是是否显示菜单项~当然只有在有vod的URL的情况下才显示,
//否则多出个menuitem多难看~
//这里注意那些id的匹配~

callProcess:function(path,args){
var file = Components.classes[“@mozilla.org/file/local;1”]
.createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(path);
var process = Components.classes[“@mozilla.org/process/util;1”]
.createInstance(Components.interfaces.nsIProcess);
process.init(file);
process.run(false, args, args.length);
},
//firefox调用外部程序,我稍微包装了下,参数为程序路径和穿的参数
//这里参数也就是vod视屏的链接啦

play:function(){
var path =Components.classes[“@mozilla.org/preferences-service;1”]
.getService(Components.interfaces.nsIPrefBranch)
.getCharPref(“sjtu.comic.mplayer”);
var URL = comic.getURL();
var args = [];
args.push(URL);
comic.callProcess(path,args);
}
};
//播放函数,当在菜单中点击时就调用这个,其先从配置中读取mplayer的位置

window.addEventListener(“load”, function(e) { comic.onLoad(e); }, false);
//这个自己理解:)

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

三. 小结

总觉得在关键的地方写的太少了~算了反正代码也不长,读起来也不算太难大家自己
理解理解吧:)这个版本是被我“和谐”后的~也就是隐藏了#XX#功能后的版本,也做了
很大的简化,在linux下是非常正常的运行的,windows下只能搞搞文件路径中没有中文
的。当然,当做教学使用应该是足够了。有什么问题和建议都欢迎来GNULinux提~也欢迎
更多的人参与到开发中来,体验开发的乐趣:)

代码:(xpi文件)
http://bbs.sjtu.edu.cn/file/GNULinux/1234626218274327.xpi

附一:
对于mplayer:
linux下推荐使用打过utf的vod补丁的,推荐smplayer前端
扩展配置中直接输入位置,如/usr/local/bin/mplayer,/usr/local/bin/smplayer

windows下推荐使用ww编译版(http://mplayer-ww.sourceforge.net/)
扩展配置重输入位置,斜杆需转义,如C:\Program Files\mplayermplayer.exe

附二:
开发出来的扩展的打包:用压缩软件打包成zip格式文件,然后修改后缀为xpi即可

==================>>>>>> <<<<<<=====================
code ( 稍有修改 ):

overlay.jsvar comic = {
onLoad: function() {
this.initialized = true;
document.getElementById(“contentAreaContextMenu”)
.addEventListener(“popupshowing”,this.showContextMenu,false);
},

getURL:function(){
var URL;
if (gContextMenu && gContextMenu.onLink) {
var result = gContextMenu.linkURL.match(/.(.rmvb|.avi|.flv|.mp3)./ig);
if(result) {
URL = encodeURI(result);
URL = unescape(URL);
}
return URL;
}
},

showContextMenu: function() {
document.getElementById(“play-comic”).hidden = true;
if (comic.getURL()) {
document.getElementById(“play-comic”).hidden = false;
}
},

callProcess:function(path,args){
var file = Components.classes[“@mozilla.org/file/local;1”]
.createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(path);
var process = Components.classes[“@mozilla.org/process/util;1”]
.createInstance(Components.interfaces.nsIProcess);
process.init(file);
process.run(false, args, args.length);
},

play:function(){
var path =Components.classes[“@mozilla.org/preferences-service;1”].
getService(Components.interfaces.nsIPrefBranch).getCharPref(“sjtu.comic.mplayer”);
var URL = comic.getURL();
var args = [];
args.push(URL);
comic.callProcess(path,args);
},

};
window.addEventListener(“load”, function(e) { comic.onLoad(e); }, false);