手把手教你快速开发新浪微博的Firefox插件(1)
Firefox的插件机制
对于一个Firefox插件来说,我们首先需要了解的它的组织结构。打开一个Firefox插件工程,你一般会看这么几个元素:chrome文件夹,defaults文件夹,chrome.manifest, install.rdf。
我们先从install.rdf说起,相比从文件名你就明白了这个文件是要干什么的。没错,这个文件就是Firefox插件的安装文件。
- <!--?xml version="1.0"?-->
- <RDF xmlns:em="http://www.mozilla.org/2004/em-rdf#">
- <DESCRIPTION about="urn:mozilla:install-manifest">
- <EM:ID>flashcard@gmail.com</EM:ID>
- <EM:VERSION>0.7</EM:VERSION>
- <EM:TYPE>2</EM:TYPE>
- <EM:NAME>flashcard</EM:NAME>
- <EM:DESCRIPTION>Post the selected word to Sina weibo.</EM:DESCRIPTION>
- <EM:HOMEPAGEURL>https://feihe.cnblogs.com</EM:HOMEPAGEURL>
- <EM:ICONURL>chrome://flashcard/skin/icon.png</EM:ICONURL>
- <EM:CREATOR>Fei He</EM:CREATOR>
- <EM:TARGETAPPLICATION>
- <DESCRIPTION>
- <EM:ID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</EM:ID>
- <EM:MINVERSION>3.0</EM:MINVERSION>
- <EM:MAXVERSION>4.0.*</EM:MAXVERSION>
- </DESCRIPTION>
- </EM:TARGETAPPLICATION>
- </DESCRIPTION>
- </RDF>
里面也就是对于你的Firefox插件的一些描述信息,其中比较关键的两个, 在根节点description下的是你的Firefox插件的id,也就是说这个东西必须唯一(至少在你的Firefox所有插件中唯一),另一个位于的下的则是Firefox的id,这个是不能修改的。再就是和,它们用来描述你的Firefox插件对于Firefox版本的兼容性。
接着我们来了解defaults,一句话defaults就是你的Firefox插件的preferences的default设置。
对于一个Firefox插件最核心的部分就是chrome.manifest和chrome文件夹。chrome.manifest有点像.NET的project文件,基本上就是对于整个Firefox插件所有元素的位置信息,而Firefox本身就是通过这个这个manifest来定位具体的元素。那么一个Firefox插件会包含那些元素呢?打开chrome.manifest你就一目了然了。
overlay chrome://browser/content/browser.xul chrome://flashcard/content/overlay.xul
content flashcard chrome/content/flashcard/
skin flashcard classic chrome/skin/classic/flashcard/
locale flashcard en-US chrome/locale/flashcard/en-US/
style chrome://global/content/customizeToolbar.xul chrome://flashcard/skin/skin.css
这里面的结构基本都是行结构的,每一个行的头就是具体的Firefox插件元素名称,而后面的是告诉Firefox去那个位置查找这个元素。而这其中包含了这么几个元素:
◆ overlay: 指向你的Firefox插件的一个UI元素,包括contextmenu,toolbar,navigator bar之类。在上面的manifest中你看我这里指向了一个后缀名是xul的文件,其实它的全称是Xml User Interface。顾名思义就是使用xml的格式来描述UI。
- <!--?xml version="1.0"?-->
- <!--?xml-stylesheet href="chrome://flashcard/skin/skin.css" type="text/css"?-->
- <OVERLAY id=flashcardOverlay>
- <SCRIPT type=application/x-javascript><!--mce:0--></SCRIPT>
- <SCRIPT type=application/x-javascript><!--mce:1--></SCRIPT>
- <SCRIPT type=application/x-javascript><!--mce:2--></SCRIPT>
- <SCRIPT type=application/x-javascript><!--mce:3--></SCRIPT>
- <SCRIPT type=application/x-javascript><!--mce:4--></SCRIPT>
- <SCRIPT type=application/x-javascript><!--mce:5--></SCRIPT>
- <SCRIPT type=application/x-javascript><!--mce:6--></SCRIPT>
- <MENUPOPUP id=contentAreaContextMenu>
- <MENUSEPARATOR id=separator_flashcard>
- <MENUITEM id=menuitem_flashcard_add class=menuitem-iconic image="chrome://flashcard/skin/word.png">
- </MENUITEM></MENUSEPARATOR></MENUPOPUP>
- </OVERLAY>
上面是我用的一个overlay.xul, 我这里是给Firefox的contextmenu加了一个新的menuitem,并使用separator和原有的menuitems分隔起来。这里的文件名是可以随意取的,那是你起的名字必须在chrome.manifest中应用。到这里很多人好奇,那么你加的menuitem相应的行为在那里呢?细心的你也许发现我这个xul中引用了一些javascript,而对于我们menuitem,Firefox提供了2中方法去关联行为:第一种就是在control的oncommand中直接指定control的行为;第二中是javascript中使用document.getElementByID来获取control从而绑定行为:
- <DIALOG id=dialog_login title=FlashCard persist="screenX screenY width height"
- windowtype="DialogWindowType"
- buttons="accept,cancel"
- onload="window.sizeToContent();"
- ondialogaccept="return login();">
- </DIALOG>
- document.getElementById("menuitem_flashcard_add").addEventListener("click", function(event){}, false);
并且,我也在这个文件中指定了css文件。其实对于xul文件中javascript和css的使用和html都基本一致。
◆ content: 就是你的Firefox插件的核心,包括javascript脚本和XUL
◆ skin:即使皮肤,你可以在给你的插件做不同的皮肤,我的mainifest中指定了我使用classic的皮肤,所以我在skin文件夹下就应classic的文件夹来对应。
◆ locale:国际化,对于我们Firefox插件中需要需要国家化的UI control, 我们可以使用它的label属性,同时在chrome.manifest中指定的culture文件夹下定义dtd文件来对应,例如: overlay.xul中的control定义:
- <MENUITEM id=menuitem_flashcard_add class=menuitem-iconic
- image="chrome://flashcard/skin/word.png" label="&flashcard.menuitem.label;">
- </MENUITEM>
dtd文件的定义:
- <!--ENTITY flashcard.menuitem.label "Post to flashcard"-->
它们之间使用control的label属性关联,而overlay.xul具体和chrome.manifest指定culture文件夹下的那个dtd文件关联,你可以看到在我的overlay.xul中有这么一句定义:
◆ style: 也就是overlay的一些样式,比如css。
你的Firefox插件有了UI,也有了相应的行为和样式,那么你还需要什么呢?需要存储,也就是你需要存储一些preferences信息或者其他的比如我这里我需要存储新浪微博中用户授权通过之后获得的Oauth_token的相关信息。Firefox对于存储提供了很多方式,你可文件存贮在特殊位置,或者使用sqlite这种肖的文件数据库。另外一种最简单的也就是我采用的就是preferences的存贮。对于Firefox插件,你可以在你的install.rdf中注明你的preference文件,这样你可以让用户使用的preference文件做一些设置,并保存。而我这里我指希望使用preferences来存贮,所以我并不希望用户看到它,那么我就不需要在install.rdf中注明。
preference文件也是一个xul文件,所以你也可以应用javascript和css,来对于你的preference中的control进行行为的绑定和样式的渲染。我这里的preference如下:
- <!--?xml version="1.0"?-->
- <!--?xml-stylesheet href="chrome://global/skin/" type="text/css"?-->
- <PREFWINDOW>
- <PREFPANE label="Flash Card Preferences">
- <PREFERENCES>
- <PREFERENCE id=pref_access_token name="Sina.WeiBo.oauth.access_token" type="string">
- <PREFERENCE id=pref_access_token_secret name="Sina.WeiBo.oauth.access_token_secret" type="string">
- </PREFERENCE></PREFERENCE></PREFERENCES>
- </PREFPANE></PREFWINDOW>
而这其中的preferences节点中的内容便是用来做preference存贮的,你可以像我一样通过
- Components.classes["@mozilla.org/preferences-service;1"].getService
- (Components.interfaces.nsIPrefService).getBranch("Sina.WeiBo.")
来获得所有name前缀为Sian.Weibo的preference,然后调用它的getCharPref('oauth.access_token')来获取值,或者通过setCharPref('oauth.access_token')设置值,对于preference,MDN上有详细的API介绍。对于在preference中引用javascript比较tricky的一点就是如果在你preference中使用prePanel,那么javascript的引用代码一定要在prePanel后面,否则你的prePanel就什么都看不到了。
最后一点,有些时候也许你希望你的Firefox插件在完成某些行为之后给用户一个notification,在Firefox3中你可以使用普通的notification或者alert,而在Firefox4中你可以使用popupNotification,效果非常炫,而且还可以指定图片和相应的action,使得用户在得到这个notification之后可以做进一步的行为。示例如下:
- PopupNotifications.show(gBrowser.selectedBrowser, "flashcard-add",
- '"'+ selectedWord +'" 已经成功加入你的单词本',
- null,
- {
- label: "确定",
- accessKey: "D",
- callback: function() {
- }
- },
- [
- {
- label: "Reset",
- accessKey: "R",
- callback: function() {
- Browser.Preferences.clearUserPref("oauth.access_token");
- Browser.Preferences.clearUserPref("oauth.access_token_secret");
- }
- },
- ]);
而指定图片则要在css中
- .popup-notification-icon[popupid="flashcard-add"] {
- list-style-image: url("chrome://flashcard/skin/icon.png");
- }
这里是我在快速开发一个Firefox插件中获得知识,如果你希望更详细的知识还是需要参考MDN。写到这里发现篇幅有点长,还是决定分为上,下两篇。下篇来讲Sina WeiBo的Oauth授权机制。