上节我们做了一个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>sessionstore@xuldev.org</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进行保存和再次打开,这个是不是有些实用了呢~