首先说明下,博客园火狐版插件安装后,在工具栏没有logo,只有右键菜单,状态栏有。
参考资料:firefox开发详细指南(中文) http://blog.csdn.net/z6482/article/details/7317766
http://blog.csdn.net/sding/article/details/5697652
http://blog.csdn.net/jxfengzi/article/details/4775352
http://blog.csdn.net/chenyanxu/article/details/3973545
http://blog.csdn.net/Xscarlet/article/details/1708102
1.插件下到本地后,将后缀名.xpi修改为.zip,解压后得到目录文件cnblogswz,目录结构如下:
. │ chrome.manifest //设置资源路径 │ install.rdf //安装信息描述文件 │ ├─defaults │ └─preferences │ cwz.js //保存option.xul配置的数值 │ └─content
cwz.js //js函数,供cwz.xul调用。向博客园服务器发送请求,提交数据 cwz.xul //配置‘添加到博客园’右键弹出窗体,添加成功提示窗体,登陆提示窗体
logo_small.gif //logo图片
option.xul //配置设置窗体
overlay.js //js函数,供overlay.xul调用。单击子菜单‘添加到博客园’的左右键事件
overlay.xul //配置菜单项
2.对目录文件遍历分析
根目录:
install.rdf 描述了扩展安装所需要的信息,包括了扩展的标识、版本、适用的应用程序、作者等等等等。
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest"> //设置插件安装路径资源文件
<em:id>contact@cnblogs.com</em:id> //设置id,保证与其他插件id不一致即可
<em:version>1.2</em:version> //插件版本
<em:targetApplication>
<Description>
//表明此扩展是针对firefox的,而不是thunderbird、sunbird,所以,只要是针对firefox的扩 展,此id的值都不变。
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>3.0</em:minVersion> //支持火狐浏览器最低版本
<em:maxVersion>9.*</em:maxVersion> //支持火狐浏览器最高版本
</Description>
</em:targetApplication>
<em:name>CnblogsWz(博客园网摘)</em:name> //插件名称
//插件描述
<em:description>This is a Cnblogs Wz plug-in, you can bookmark article to Cnblogs Wz(这是一个博客园网摘插件,可以收藏文章到博客园网摘)</em:description>
<em:optionsURL>chrome://cwz/content/option.xul</em:optionsURL> //插件设置项路径
<em:creator>博客园</em:creator>
</Description>
</RDF>
chrome.manifest 让fierfox找到扩展的content、locale、skin文件在哪里
content cwz content/ //指明,包名为cwz(类似于java中的包名),content类型文件在content子目录下
//指明,chrome://cwz/content/overlay.xul加载到chrome://browser/content/browser.xul中
overlay chrome://browser/content/browser.xul chrome://cwz/content/overlay.xul
defaults目录:
cwz.js 保存设置面板中设置的数值,在option.xul中会对其引用
pref("extensions.cwz.showContextMenu", true);
pref("extensions.cwz.showStatusBarIcon", true);
pref("extensions.cwz.quickClose", false);
pref("extensions.cwz.silentPost", false);
content目录:
logo_small.gif logo图片在cwz.xul中有引用
option.xul
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" windowtype="cwzoption" title="设置">
<prefpane>
<preferences>
//类型为boolean,初始值为true,对应cwz.js中pref("extensions.cwz.quickClose", false);
<preference id="quickClose" name="extensions.cwz.quickClose" instantApply="true" type="bool" />
//类型为boolean,初始值为true,对应cwz.js中pref("extensions.cwz.silentPost", false);
<preference id="silentPost" name="extensions.cwz.silentPost" instantApply="true" type="bool" />
</preferences>
<groupbox>
<checkbox preference="quickClose" label="立即关闭窗口(不等待3秒)"/> //UI显示,取值对应preference中的quickClose
<checkbox preference="silentPost" label="静默方式(不弹窗)"/> //UI显示,取值对应preference中的silentPost
</groupbox>
</prefpane>
</prefwindow>
overlay.xul 设置菜单UI
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE overlay SYSTEM "chrome://httpresponsereplace/locale/browserOverlay.xul.dtd">
<overlay id="cwz-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
//加载鼠标事件处理js
<script src="overlay.js"/>
//在工具栏中添加子菜单
<toolbarpalette id="BrowserToolbarPalette">
<toolbarbutton>...</toolbarbutton>
</toolbarpalette>
//在状态栏中添加子菜单
<statusbar id="status-bar">
<statusbarpanel id="cwz-status">
...
</statusbarpanel>
</statusbar>
//在鼠标右键菜单中添加子菜单
<popup id="contentAreaContextMenu">
<menuitem id="cwz-context" label="添加到博客园网摘" insertafter="context-stop" onclick='cwz.showWindow(event)'/>
</popup>
</overlay>
overlay.js 菜单事件
//监听器
var cwz = {
init: function () {
},
showWindow: function (event) {
//单击左键事件
if (event.button == 0) {
//获取包cwz的配置
var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.cwz.");
//取配置项silentPost数值
var a = prefs.getBoolPref("silentPost");
//如果配置为不弹出对话框,则直接向博客园提交网摘数据
if (a) {
var currentWebDoc = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService().QueryInterface(Components.interfaces.nsIWindowMediator).
getMostRecentWindow("navigator:browser").getBrowser().mCurrentBrowser.contentDocument;
var xmlHttp = new XMLHttpRequest;
xmlHttp.open("get", 'http://home.cnblogs.com/wz/AddWZ?url=' + currentWebDoc.location + '&title=' + escape(currentWebDoc.title), true);
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.send();
return;
}
//否则打开添加网摘的UI
window.open("chrome://cwz/content/cwz.xul", "cwz", "chrome,resizable=no,centerscreen", this);
var win = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow("cwz");
if (win) {
win.focus();
}
//单击右键事件
} else if (event.button == 2) {
//打开设置对话框UI
window.openDialog("chrome://cwz/content/option.xul", "cwzoption", "chrome,resizable=no,centerscreen", this);
//获取对话框句柄
var win = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator).
getMostRecentWindow("cwzoption");
//聚焦
if (win) {
win.focus();
}
}
}
}
//添加监听器
window.addEventListener("load", cwz.init, false);
cwz.xul 添加网摘UI
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
//执行js中onload()
<window onload="onLoad()" xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
width="400" height="345" title="博客园网摘" windowtype="cwz">
//加载事件处理js
<script src="cwz.js"></script>
//横向盒子
<vbox style="padding-left:15px;padding-top:5px;">
//竖盒子
<hbox height="48" style="border-bottom:1px solid #CCCCCC;padding-bottom:3px;margin-bottom:5px;">
//引用logo图片
<image height="45" src="logo_small.gif"/>
<spacer flex="1"/>
//横盒子
<vbox height="45">
<spacer flex="1"/>
//设置连接
<label class="text-link" href="http://home.cnblogs.com/wz/" value="我的网摘"/>
</vbox>
<spacer flex="0"/>
<hr/>
</hbox>
<vbox id="panel_add">
<hbox height="28" style="padding-top:3px;">
<label control="tb_url" value="网址:"/>
<textbox id="tb_url" width="300" multiline="false" cols="100"/>
</hbox>
<hbox height="28" style="padding-top:3px;">
<label control="tb_title" value="标题:"/>
<textbox id="tb_title" width="300" multiline="false" cols="100"/>
</hbox>
<hbox height="28" style="padding-top:3px;">
<label control="tb_tags" value="标签:"/>
<textbox id="tb_tags" multiline="false" width="200" cols="70"/>
<a id="select_block" onclick="showTag()">选择标签</a>
<label style="color:Green" value="(逗号隔开)"/>
</hbox>
<hbox>
<stack id="tagselect" style="display:none;200px">
<vbox style="border: 2px solid #97ACD2;margin:10px;">
<hbox style="border-bottom:1px solid #CCC;padding:5px;padding-bottom:2px;">
<hbox style="color:#999">选择tag</hbox>
<hbox onclick="closeTag()" style="margin-left:258px;cursor:pointer;">关闭</hbox>
</hbox>
<vbox style="height:100px;overflow:auto">
<description id="editMenu" align="start" left="0" right="0">
<html:div id="tags_box"></html:div>
</description >
</vbox>
</vbox>
</stack>
</hbox>
<hbox height="105" style="padding-top:3px;">
<label control="ta_summary" value="摘要:"/>
<vbox>
<textbox id="ta_summary" multiline="true" rows="4" cols="44"/>
<label style="color:Green" value="(不超过200字)"/>
</vbox>
</hbox>
<hbox height="20">
<spacer style="44px" flex="0"/>
<checkbox id="isPrivate" label="私有网摘" checked="false"/>
</hbox>
<hbox>
<spacer style="44px" flex="0"/>
//按钮,单击后触发事件
<button oncommand="addwz()" id="btnaddwz" style="45px;min-1em;height:20px;" label="收藏"/>
</hbox>
</vbox>
<vbox>
<label id="as" style="padding:10px;color:Red" value=""/>
//隐藏的盒子
<label id="loginl" style="padding-left:10px;display:none;color:Red" class="text-link" href="http://passport.cnblogs.com/login.aspx" value="点此进行登录"/>
<label id="closet" style="padding-left:10px;display:none;color:Green;" value="3秒后本窗口将自动关闭。"/>
</vbox>
</vbox>
//div
<div id="tag_box"></div>
</window>
cwz.js
function onLoad()
{
//获取当前网页doc
var currentWebDoc = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService().QueryInterface(Components.interfaces.nsIWindowMediator).getMostRecentWindow("navigator:browser").
getBrowser().mCurrentBrowser.contentDocument;
//为盒子中的tb_url赋值
document.getElementById("tb_url").value = currentWebDoc.location;
document.getElementById("tb_title").value = currentWebDoc.title;
}
//html编码
function htmlEncode(str) {
//获取所有的div标签句柄
var div = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
div.textContent = str;
//转换为innerHTML
return div.innerHTML;
}
//添加网摘
function addwz()
{
var isprivate = "on";
if (document.getElementById("isPrivate").checked) {
isprivate = "";
}
var wz = {};
wz.url = document.getElementById("tb_url").value;
wz.title = document.getElementById("tb_title").value;
wz.tags = document.getElementById("tb_tags").value;
wz.summary = document.getElementById("ta_summary").value;
wz.isPrivate = isprivate;
if (wz.tags.length > 0) {
wz.tags = wz.tags.replace(/,/g, ',');
}
if (wz.summary.length > 200) {
wz.summary = wz.summary.substring(0, 200);
}
document.getElementById("btnaddwz").label = "please wait...";
document.getElementById("btnaddwz").style.width = "100px";
document.getElementById("btnaddwz").disabled = true;
var xmlHttp = new XMLHttpRequest;
//请求
xmlHttp.open("get", 'http://home.cnblogs.com/wz/AddWZ?url=' + encodeURIComponent(wz.url) + '&title=' + encodeURIComponent(htmlEncode(wz.title)) + '&tags=' + encodeURIComponent(wz.tags) + '&summary=' + encodeURIComponent(htmlEncode(wz.summary)) + '&isPrivate=' + wz.isPrivate, true);
//回调函数
xmlHttp.onreadystatechange=function()
{
//获得异步回执
if(xmlHttp.readyState==4)
{
//返回成功
if(xmlHttp.status==200)
{
//显示登录提示
if(xmlHttp.responseText.length==4)
{
document.getElementById("as").value=xmlHttp.responseText;
document.getElementById("panel_add").style.display="none";
document.getElementById("loginl").style.display="block";
}
//显示添加成功提示
else
{
document.getElementById("as").value=xmlHttp.responseText;
document.getElementById("panel_add").style.display="none";
document.getElementById("closet").style.display="block";
var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.cwz.");
//获取cwz.js中配置项quickClose
var a = prefs.getBoolPref("quickClose");
if (a)
{
window.opener=null;
window.close();
}
else
{
//3秒后关闭窗口
setTimeout("window.opener=null;window.close()",3000);
}
}
}
}
}
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//发送请求
xmlHttp.send(true);
}
//选中标签并设置css样式
function $(ID) {
var element = document.getElementById(ID);
if (element) {
element.css = css;
}
return element;
}
//设置css样式
function css(prop, value) {
if (value == null) {
return this.style[prop];
}
if (prop) {
this.style[prop] = value;
}
return true;
}
//添加tag事件
function addTag(tagName) {
var TagStr = document.getElementById("tb_tags").value;
//将tagName添加到tb_tags中
if (TagStr.indexOf(tagName) == -1) {
if (TagStr == '')
TagStr = TagStr + tagName;
else
TagStr = TagStr + "," + tagName;
document.getElementById("tb_tags").value = TagStr;
}
}
//显示标签
function showTag() {
//如果tags_box已有内容则,显示选择项
if ($("tags_box").textContent.length > 1) {
$("tagselect").css("display", "block");
}
else {
//向博客园查询已创建的标签
var xmlHttp = new XMLHttpRequest;
xmlHttp.open("get", 'http://home.cnblogs.com/wz/GetUserTags', true);
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
//回调函数
showTag_CallBack(xmlHttp.responseText);
}
}
}
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.send(true);
}
}
//显示标签的回调函数
function showTag_CallBack(data) {
$("tagselect").css("display", "block");
$("select_block").css("cursor", "default");
data = data.slice(5, -6);
$("tags_box").innerHTML = data;
}
//关闭选择
function closeTag() {
$("tagselect").css("display", "none");
$("select_block").css("cursor", "pointer");
}
--OVER