博客园网摘firefox插件源码分析

首先说明下,博客园火狐版插件安装后,在工具栏没有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








原文地址:https://www.cnblogs.com/zhuri/p/2672276.html