Mozilla Firefox扩展(Extensions)开发——XPCOM&XUL(二)

上节我们做了一个hello world,然而并没有什么卵用。这节我们实现一个具有实用功能的扩展吧!

创建我们的扩展开发目录,其结构如下:

sessionstore

|——content

|             |——overlay.js

|               | ——overlay.xul

|                 | ——prefs.xul

|——defaults

|                  |——preferences

|                                    |——sessionstore-prefs.js

|——chrome.manifest

|——install.rdf

各文件的实现如下:

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">
    <!-- Unique ID for extension. Can be in e-mail address format or GUID format -->
    <em:id>[email protected]</em:id>
    <!-- Indicates that this add-on is an extension -->
    <em:type>2</em:type>
    <!-- Extension name displayed in Add-on Manager -->
    <em:name>Hello, World!</em:name>
    <!-- Extension version number. There is a version numbering scheme you must follow -->
    <em:version>0.1</em:version>
    <!-- Brief description displayed in Add-on Manager -->
    <em:description>My sessionstore extension.</em:description>
    <!-- Name of extension's primary developer. Change to your name -->
    <em:creator>Gomita</em:creator>
    <!-- Web page address through which extension is distributed -->
    <em:homepageURL>http://www.xuldev.org/helloworld/</em:homepageURL>
    <!-- This section gives details of the target application for the extension (in this case: Firefox 2) -->
    <em:targetApplication>
      <Description>
        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
        <em:minVersion>2.0</em:minVersion>
        <em:maxVersion>4.0.0.*</em:maxVersion>
      </Description>
    </em:targetApplication>
	<em:optionsURL>chrome://sessionstore/content/prefs.xul</em:optionsURL>
  </Description>
</RDF> 

chrome.manifest

content sessionstore content/
overlay chrome://browser/content/browser.xul chrome://sessionstore/content/overlay.xul

overlay.xul

<?xml version="1.0"?>
<overlay id="sessionstoreOverlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <script type="application/javascript"
      src="chrome://sessionstore/content/overlay.js" />
    <menupopup id="menu_ToolsPopup">
      <menu label="Session Store" insertbefore="sanitizeSeparator">
        <menupopup onpopupshowing="gSessionStore.createMenu(event);" oncommand="gSessionStore.restore(event);">
		  <menuitem label="Save Session" oncommand="gSessionStore.save(event);" />
		  <menuseparator />
		  <!-- Dynamically generated menu items go here -->
		  <menuseparator />
		  <menuitem label="Clear Sessions" oncommand="gSessionStore.clear(event);" />
		</menupopup>
    </menu>
  </menupopup>
</overlay>

overlay.js(这个代码看起来比较乱,实际上就是一个函数数组)

var gSessionStore = {
  // Directory to save sessions (nsILocalFile)
  _dir: null,
  // Initialization
  init: function() {
  var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
               .getService(Components.interfaces.nsIProperties);
  this._dir = dirSvc.get("ProfD", Components.interfaces.nsILocalFile);
  this._dir.append("sessionstore");
  if (!this._dir.exists())
    this._dir.create(this._dir.DIRECTORY_TYPE, 0700);
	},
  // uninitialization
  uninit: function() {
  this._dir = null;
},
  // Save session (event handler)
  save: function(event) {
  event.stopPropagation();
  var ss = Components.classes["@mozilla.org/browser/sessionstore;1"]
           .getService(Components.interfaces.nsISessionStore);
  var state = ss.getBrowserState();
  var fileName = "session_" + Date.now() + ".js";
  var file = this._dir.clone();
  file.append(fileName);
  this._writeFile(file, state);
},
  // Restore session (event handler)
  restore: function(event) {
  var fileName = event.target.getAttribute("fileName");
  var file = this._dir.clone();
  file.append(fileName);
  var state = this._readFile(file);
  var ss = Components.classes["@mozilla.org/browser/sessionstore;1"]
           .getService(Components.interfaces.nsISessionStore);
  ss.setWindowState(window, state, false);
},
  // Delete session (event handler)
  clear: function(event)
  {
    event.preventBubble();
    var fileEnum = this._dir.directoryEntries;
    while (fileEnum.hasMoreElements()) {
      var file = fileEnum.getNext().QueryInterface(Components.interfaces.nsIFile);
      file.remove(false);
      // debug
      dump("SessionStore> clear: " + file.leafName + "\n");
    }
  },
  // Dynamically generate menu items (event handler)
  createMenu: function(event)
  {
    var menupopup = event.target;
    for (var i = menupopup.childNodes.length - 1; i >= 0; i--) {
      var node = menupopup.childNodes[i];
      if (node.hasAttribute("fileName"))
        menupopup.removeChild(node);
    }
    var fileEnum = this._dir.directoryEntries;
    while (fileEnum.hasMoreElements()) {
      var file = fileEnum.getNext().QueryInterface(Components.interfaces.nsIFile);
      var re = new RegExp("^session_(\\d+)\.js$");
      if (!re.test(file.leafName))
        continue;
      var dateTime = new Date(parseInt(RegExp.$1, 10)).toLocaleString();
      var menuitem = document.createElement("menuitem");
      menuitem.setAttribute("label", dateTime);
      menuitem.setAttribute("fileName", file.leafName);
      menupopup.insertBefore(menuitem, menupopup.firstChild.nextSibling.nextSibling);
    }
  },
   // Read file
  _readFile: function(aFile)
  {
    try {
      var stream = Components.classes["@mozilla.org/network/file-input-stream;1"].
                   createInstance(Components.interfaces.nsIFileInputStream);
      stream.init(aFile, 0x01, 0, 0);
      var cvstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
                     createInstance(Components.interfaces.nsIConverterInputStream);
      cvstream.init(stream, "UTF-8", 1024, Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
      var content = "";
      var data = {};
      while (cvstream.readString(4096, data)) {
        content += data.value;
      }
      cvstream.close();
      return content.replace(/\r\n?/g, "\n");
    }
    catch (ex) { }
    return null;
  },

  // Write file
  _writeFile: function(aFile, aData)
  {
    // init stream
    var stream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"].
                 createInstance(Components.interfaces.nsIFileOutputStream);
    stream.init(aFile, 0x02 | 0x08 | 0x20, 0600, 0);
    // convert to UTF-8
    var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].
                    createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
    converter.charset = "UTF-8";
    var convertedData = converter.ConvertFromUnicode(aData);
    convertedData += converter.Finish();
    // write and close stream
    stream.write(convertedData, convertedData.length);
    if (stream instanceof Components.interfaces.nsISafeOutputStream) {
      stream.finish();
    } else {
      stream.close();
    }
  },
};
window.addEventListener("load", function(){
gSessionStore.init(); }, false);
window.addEventListener("unload", function(){
gSessionStore.uninit(); }, false);

prefs.xul

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<prefwindow id="sessionstorePrefs" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
     title="Session Store Preferences">
  <prefpane>
    <preferences>
      <preference id="extensions.sessionstore.warnOnClear"
           name="extensions.sessionstore.warnOnClear"
           type="bool" />
      <preference id="extensions.sessionstore.replaceTabs"
           name="extensions.sessionstore.replaceTabs"
           type="int" />
    </preferences>
    <checkbox label="Confirm before clearing sessions"
         preference="extensions.sessionstore.warnOnClear" />
    <groupbox>
      <caption label="When restoring session:" />
      <radiogroup preference="extensions.sessionstore.replaceTabs">
        <radio value="0" label="Keep current tabs" />
        <radio value="1" label="Replace current tabs"/>
        <radio value="2" label="Ask me every time" />
      </radiogroup>
    </groupbox>
  </prefpane>
</prefwindow>

sessionstore-prefs.js

pref("extensions.sessionstore.warnOnClear", true);
pref("extensions.sessionstore.replaceTabs", 2);

参看上节的方法进行打包安装后,就可以看到效果啦,可以对自己访问的页面session进行保存和再次打开,这个是不是有些实用了呢~

时间: 2024-12-28 23:49:37

Mozilla Firefox扩展(Extensions)开发——XPCOM&XUL(二)的相关文章

Mozilla Firefox扩展(Extensions)开发——xulrunner

XULRunner is a Mozilla runtime package that can be used to bootstrap XUL+XPCOM applications that are as rich as Firefox and Thunderbird. It provides mechanisms for installing, upgrading, and uninstalling these applications. XULRunner also provides li

Firefox扩展开发

Firefox扩展开发 (插件开发) Extension开发 入门教程 5步走 五步走 首先需要知道什么是"Firefox插件".这里说的"插件"只是一个通俗的说法,其实Firefox这种扩展功能的"插件"包括:扩展extension和插件plugin. {tip:title=Handy Hint} Firefox官方网站的解释是:Extensions are small add-ons that add new functionality to

Firefox 扩展开发手记

2015.7.14 因工作,想写一个能实现将 Excel 中的信息自动提交到网页表单的工具,决定开发一个插件试验一下.第一次开发 FF 插件,也决定写一下开发日志,一方面和大家分享经验,另一方面也是希望能坚持到底 今天主要做了信息收集. 了解到基本上只需要 XML 和 Javascrtip 就可以了 FF 官方开发中心 https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/Getting_Started

【COCOS2DX-LUA 脚本开发之十二】Hybrid模式-利用AssetsManager实现在线更新脚本文件lua、js、图片等资源(免去平台审核周期)

转载自:http://www.himigame.com/iphone-cocos2dx/1354.html 首先说明一个问题: 为什么要在线更新资源和脚本文件!? 对于此问题,那要说的太多了,简单概括,如果你的项目已经在google play 或Apple Store 等平台上架了,那么当你项目需要做一些活动或者修改前端的一些代码等那么你需要重新提交一个新版本给平台,这时候你的上架时候是个不确定的时候,具体什么时候能上架,主要跟平台有关,你再着急,也没有用的. 那么如果你的项目是使用脚本语言进行

iOS开发-定制多样式二维码

iOS开发-定制多样式二维码 二维码/条形码是按照某种特定的几何图形按一定规律在平台(一维/二维方向上)分布的黑白相间的图形纪录符号信息.使用若干个与二进制对应的几何形体来表示文字数值信息. 最常见的二维码功能包括信息获取.网站跳转.电商交易.手机支付等等,其拥有密度小.信息容量大.容错能力强.成本低.制作难度低等优点.在移动开发中,二维码的地位也越来越重要,掌握二维码的基本操作是重要的本领之一. 在iOS7之后,苹果自身集成了二维码的生成和读取功能.生成二维码包括以下步骤 1.导入CoreIm

微信公众平台开发(十二) 发送客服消息

原文:微信公众平台开发(十二) 发送客服消息 一.简介 当用户主动发消息给公众号的时候(包括发送信息.点击自定义菜单.订阅事件.扫描二维码事件.支付成功事件.用户维权),微信将会把消息数据推送给开发者,开发者在一段时间内(目前修改为48小时)可以调用客服消息接口,通过POST一个JSON数据包来发送消息给普通用户,在48小时内不限制发送次数.此接口主要用于客服等有人工消息处理环节的功能,方便开发者为用户提供更加优质的服务. 二.思路分析 官方文档中只提供了一个发送客服消息的接口,开发者只要POS

Drupal常用开发工具(二)——Drupal for Firebug

Drupal 的开发工具有很多,除了<Drupal常用开发工具(一)——Devel模块>中提到的 Devel 模块外,Drupal for Firebug 也是很重要的 Drupal 开发工具. 请注意 Drupal for Firebug 可能与 Theme Developer 模块之间存在冲突 安装 安装 DrupalForFirebug 火狐插件 (本文的所有示例均使用Firefox 版本的Firebug) 安装 Drupal for Firebug 模块 启用 Drupal for F

firefox os 手机开发之设备调用

1)话筒 权限:telephony api:navigator.moztelephony 链接参考:https://wiki.mozilla.org/WebAPI/WebTelephony 2) 扬声器 权限:audio channels选项:["normal", "content",""notification", "alarm", "telephony","ringer"]

Apache Mina开发手册之二

Apache Mina开发手册之二 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs 四.NIO概述 NIO API是Java 1.4版引入的,NIO的意思是非阻塞的I/O通信.要知道Mina的NIO是基于NIO-1开发的,而在JDK 7中引入了NIO-2的库,但Mina还没有从NIO-2中获得各方面的提升,因此Mina还是基于NIO-1的.虽然Oracle官方是把NIO的N作为New的解释,但业界普遍把这个N解释为Non-Blocking. Mina