home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 May / maximum-cd-2009-05.iso / DiscContents / Firefox Setup 3.0.6.exe / nonlocalized / components / fuelApplication.js < prev    next >
Encoding:
JavaScript  |  2009-01-19  |  37.3 KB  |  1,429 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is FUEL.
  15.  *
  16.  * The Initial Developer of the Original Code is Mozilla Corporation.
  17.  * Portions created by the Initial Developer are Copyright (C) 2006
  18.  * the Initial Developer. All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *  Mark Finkle <mfinkle@mozilla.com> (Original Author)
  22.  *  John Resig  <jresig@mozilla.com> (Original Author)
  23.  *
  24.  * Alternatively, the contents of this file may be used under the terms of
  25.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  26.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27.  * in which case the provisions of the GPL or the LGPL are applicable instead
  28.  * of those above. If you wish to allow use of your version of this file only
  29.  * under the terms of either the GPL or the LGPL, and not to allow others to
  30.  * use your version of this file under the terms of the MPL, indicate your
  31.  * decision by deleting the provisions above and replace them with the notice
  32.  * and other provisions required by the GPL or the LGPL. If you do not delete
  33.  * the provisions above, a recipient may use your version of this file under
  34.  * the terms of any one of the MPL, the GPL or the LGPL.
  35.  *
  36.  * ***** END LICENSE BLOCK ***** */
  37.  
  38. const Ci = Components.interfaces;
  39. const Cc = Components.classes;
  40.  
  41. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  42.  
  43. //=================================================
  44. // Singleton that holds services and utilities
  45. var Utilities = {
  46.   _bookmarks : null,
  47.   get bookmarks() {
  48.     if (!this._bookmarks) {
  49.       this._bookmarks = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
  50.                         getService(Ci.nsINavBookmarksService);
  51.     }
  52.     return this._bookmarks;
  53.   },
  54.  
  55.   _livemarks : null,
  56.   get livemarks() {
  57.     if (!this._livemarks) {
  58.       this._livemarks = Cc["@mozilla.org/browser/livemark-service;2"].
  59.                         getService(Ci.nsILivemarkService);
  60.     }
  61.     return this._livemarks;
  62.   },
  63.  
  64.   _annotations : null,
  65.   get annotations() {
  66.     if (!this._annotations) {
  67.       this._annotations = Cc["@mozilla.org/browser/annotation-service;1"].
  68.                           getService(Ci.nsIAnnotationService);
  69.     }
  70.     return this._annotations;
  71.   },
  72.  
  73.   _history : null,
  74.   get history() {
  75.     if (!this._history) {
  76.       this._history = Cc["@mozilla.org/browser/nav-history-service;1"].
  77.                       getService(Ci.nsINavHistoryService);
  78.     }
  79.     return this._history;
  80.   },
  81.  
  82.   _windowMediator : null,
  83.   get windowMediator() {
  84.     if (!this._windowMediator) {
  85.       this._windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].
  86.                              getService(Ci.nsIWindowMediator);
  87.     }
  88.     return this._windowMediator;
  89.   },
  90.  
  91.   makeURI : function(aSpec) {
  92.     if (!aSpec)
  93.       return null;
  94.     var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
  95.     return ios.newURI(aSpec, null, null);
  96.   },
  97.  
  98.   free : function() {
  99.     this._bookmarks = null;
  100.     this._livemarks = null;
  101.     this._annotations = null;
  102.     this._history = null;
  103.     this._windowMediator = null;
  104.   }
  105. };
  106.  
  107.  
  108. //=================================================
  109. // Window implementation
  110. function Window(aWindow) {
  111.   this._window = aWindow;
  112.   this._tabbrowser = aWindow.getBrowser();
  113.   this._events = new Events();
  114.   this._cleanup = {};
  115.  
  116.   this._watch("TabOpen");
  117.   this._watch("TabMove");
  118.   this._watch("TabClose");
  119.   this._watch("TabSelect");
  120.  
  121.   var self = this;
  122.   gShutdown.push(function() { self._shutdown(); });
  123. }
  124.  
  125. Window.prototype = {
  126.   get events() {
  127.     return this._events;
  128.   },
  129.  
  130.   /*
  131.    * Helper used to setup event handlers on the XBL element. Note that the events
  132.    * are actually dispatched to tabs, so we capture them.
  133.    */
  134.   _watch : function win_watch(aType) {
  135.     var self = this;
  136.     this._tabbrowser.addEventListener(aType,
  137.       this._cleanup[aType] = function(e){ self._event(e); },
  138.       true);
  139.   },
  140.  
  141.   /*
  142.    * Helper event callback used to redirect events made on the XBL element
  143.    */
  144.   _event : function win_event(aEvent) {
  145.     this._events.dispatch(aEvent.type, "");
  146.   },
  147.  
  148.   get tabs() {
  149.     var tabs = [];
  150.     var browsers = this._tabbrowser.browsers;
  151.  
  152.     for (var i=0; i<browsers.length; i++)
  153.       tabs.push(new BrowserTab(this._window, browsers[i]));
  154.  
  155.     return tabs;
  156.   },
  157.  
  158.   get activeTab() {
  159.     return new BrowserTab(this._window, this._tabbrowser.selectedBrowser);
  160.   },
  161.  
  162.   open : function win_open(aURI) {
  163.     return new BrowserTab(this._window, this._tabbrowser.addTab(aURI.spec).linkedBrowser);
  164.   },
  165.  
  166.   _shutdown : function win_shutdown() {
  167.     for (var type in this._cleanup)
  168.       this._tabbrowser.removeEventListener(type, this._cleanup[type], true);
  169.     this._cleanup = null;
  170.  
  171.     this._window = null;
  172.     this._tabbrowser = null;
  173.     this._events = null;
  174.   },
  175.  
  176.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIWindow])
  177. };
  178.  
  179.  
  180. //=================================================
  181. // BrowserTab implementation
  182. function BrowserTab(aWindow, aBrowser) {
  183.   this._window = aWindow;
  184.   this._tabbrowser = aWindow.getBrowser();
  185.   this._browser = aBrowser;
  186.   this._events = new Events();
  187.   this._cleanup = {};
  188.  
  189.   this._watch("load");
  190.  
  191.   var self = this;
  192.   gShutdown.push(function() { self._shutdown(); });
  193. }
  194.  
  195. BrowserTab.prototype = {
  196.   get uri() {
  197.     return this._browser.currentURI;
  198.   },
  199.  
  200.   get index() {
  201.     var tabs = this._tabbrowser.mTabs;
  202.     for (var i=0; i<tabs.length; i++) {
  203.       if (tabs[i].linkedBrowser == this._browser)
  204.         return i;
  205.     }
  206.     return -1;
  207.   },
  208.  
  209.   get events() {
  210.     return this._events;
  211.   },
  212.  
  213.   get window() {
  214.     return this._window;
  215.   },
  216.  
  217.   get document() {
  218.     return this._browser.contentDocument;
  219.   },
  220.  
  221.   /*
  222.    * Helper used to setup event handlers on the XBL element
  223.    */
  224.   _watch : function bt_watch(aType) {
  225.     var self = this;
  226.     this._browser.addEventListener(aType,
  227.       this._cleanup[aType] = function(e){ self._event(e); },
  228.       true);
  229.   },
  230.  
  231.   /*
  232.    * Helper event callback used to redirect events made on the XBL element
  233.    */
  234.   _event : function bt_event(aEvent) {
  235.     if (aEvent.type == "load") {
  236.       if (!(aEvent.originalTarget instanceof Ci.nsIDOMHTMLDocument))
  237.         return;
  238.  
  239.       if (aEvent.originalTarget.defaultView instanceof Ci.nsIDOMWindowInternal &&
  240.           aEvent.originalTarget.defaultView.frameElement)
  241.         return;
  242.     }
  243.  
  244.     this._events.dispatch(aEvent.type, "");
  245.   },
  246.  
  247.   /*
  248.    * Helper used to determine the index offset of the browsertab
  249.    */
  250.   _getTab : function bt_gettab() {
  251.     var tabs = this._tabbrowser.mTabs;
  252.     return tabs[this.index] || null;
  253.   },
  254.  
  255.   load : function bt_load(aURI) {
  256.     this._browser.loadURI(aURI.spec, null, null);
  257.   },
  258.  
  259.   focus : function bt_focus() {
  260.     this._tabbrowser.selectedTab = this._getTab();
  261.     this._tabbrowser.focus();
  262.   },
  263.  
  264.   close : function bt_close() {
  265.     this._tabbrowser.removeTab(this._getTab());
  266.   },
  267.  
  268.   moveBefore : function bt_movebefore(aBefore) {
  269.     this._tabbrowser.moveTabTo(this._getTab(), aBefore.index);
  270.   },
  271.  
  272.   moveToEnd : function bt_moveend() {
  273.     this._tabbrowser.moveTabTo(this._getTab(), this._tabbrowser.browsers.length);
  274.   },
  275.  
  276.   _shutdown : function bt_shutdown() {
  277.     for (var type in this._cleanup)
  278.       this._browser.removeEventListener(type, this._cleanup[type], true);
  279.     this._cleanup = null;
  280.  
  281.     this._window = null;
  282.     this._tabbrowser = null;
  283.     this._browser = null;
  284.     this._events = null;
  285.   },
  286.  
  287.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIBrowserTab])
  288. };
  289.  
  290.  
  291. //=================================================
  292. // Annotations implementation
  293. function Annotations(aId) {
  294.   this._id = aId;
  295. }
  296.  
  297. Annotations.prototype = {
  298.   get names() {
  299.     return Utilities.annotations.getItemAnnotationNames(this._id, {});
  300.   },
  301.  
  302.   has : function ann_has(aName) {
  303.     return Utilities.annotations.itemHasAnnotation(this._id, aName);
  304.   },
  305.  
  306.   get : function(aName) {
  307.     if (this.has(aName))
  308.       return Utilities.annotations.getItemAnnotation(this._id, aName);
  309.     return null;
  310.   },
  311.  
  312.   set : function(aName, aValue, aExpiration) {
  313.     Utilities.annotations.setItemAnnotation(this._id, aName, aValue, 0, aExpiration);
  314.   },
  315.  
  316.   remove : function ann_remove(aName) {
  317.     if (aName)
  318.       Utilities.annotations.removeItemAnnotation(this._id, aName);
  319.   },
  320.  
  321.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIAnnotations])
  322. };
  323.  
  324.  
  325. //=================================================
  326. // Bookmark implementation
  327. function Bookmark(aId, aParent, aType) {
  328.   this._id = aId;
  329.   this._parent = aParent;
  330.   this._type = aType || "bookmark";
  331.   this._annotations = new Annotations(this._id);
  332.   this._events = new Events();
  333.  
  334.   Utilities.bookmarks.addObserver(this, false);
  335.  
  336.   var self = this;
  337.   gShutdown.push(function() { self._shutdown(); });
  338. }
  339.  
  340. Bookmark.prototype = {
  341.   _shutdown : function bm_shutdown() {
  342.     this._annotations = null;
  343.     this._events = null;
  344.  
  345.     Utilities.bookmarks.removeObserver(this);
  346.   },
  347.  
  348.   get id() {
  349.     return this._id;
  350.   },
  351.  
  352.   get title() {
  353.     return Utilities.bookmarks.getItemTitle(this._id);
  354.   },
  355.  
  356.   set title(aTitle) {
  357.     Utilities.bookmarks.setItemTitle(this._id, aTitle);
  358.   },
  359.  
  360.   get uri() {
  361.     return Utilities.bookmarks.getBookmarkURI(this._id);
  362.   },
  363.  
  364.   set uri(aURI) {
  365.     return Utilities.bookmarks.changeBookmarkURI(this._id, aURI);
  366.   },
  367.  
  368.   get description() {
  369.     return this._annotations.get("bookmarkProperties/description");
  370.   },
  371.  
  372.   set description(aDesc) {
  373.     this._annotations.set("bookmarkProperties/description", aDesc, Ci.nsIAnnotationService.EXPIRE_NEVER);
  374.   },
  375.  
  376.   get keyword() {
  377.     return Utilities.bookmarks.getKeywordForBookmark(this._id);
  378.   },
  379.  
  380.   set keyword(aKeyword) {
  381.     Utilities.bookmarks.setKeywordForBookmark(this._id, aKeyword);
  382.   },
  383.  
  384.   get type() {
  385.     return this._type;
  386.   },
  387.  
  388.   get parent() {
  389.     return this._parent;
  390.   },
  391.  
  392.   set parent(aFolder) {
  393.     Utilities.bookmarks.moveItem(this._id, aFolder.id, Utilities.bookmarks.DEFAULT_INDEX);
  394.     // this._parent is updated in onItemMoved
  395.   },
  396.  
  397.   get annotations() {
  398.     return this._annotations;
  399.   },
  400.  
  401.   get events() {
  402.     return this._events;
  403.   },
  404.  
  405.   remove : function bm_remove() {
  406.     Utilities.bookmarks.removeItem(this._id);
  407.   },
  408.  
  409.   // observer
  410.   onBeginUpdateBatch : function bm_obub() {
  411.   },
  412.  
  413.   onEndUpdateBatch : function bm_oeub() {
  414.   },
  415.  
  416.   onItemAdded : function bm_oia(aId, aFolder, aIndex) {
  417.     // bookmark object doesn't exist at this point
  418.   },
  419.  
  420.   onItemRemoved : function bm_oir(aId, aFolder, aIndex) {
  421.     if (this._id == aId)
  422.       this._events.dispatch("remove", aId);
  423.   },
  424.  
  425.   onItemChanged : function bm_oic(aId, aProperty, aIsAnnotationProperty, aValue) {
  426.     if (this._id == aId)
  427.       this._events.dispatch("change", aProperty);
  428.   },
  429.  
  430.   onItemVisited: function bm_oiv(aId, aVisitID, aTime) {
  431.   },
  432.  
  433.   onItemMoved: function bm_oim(aId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
  434.     if (this._id == aId) {
  435.       this._parent = new BookmarkFolder(aNewParent, Utilities.bookmarks.getFolderIdForItem(aNewParent));
  436.       this._events.dispatch("move", aId);
  437.     }
  438.   },
  439.  
  440.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIBookmark, Ci.nsINavBookmarkObserver])
  441. };
  442.  
  443.  
  444. //=================================================
  445. // BookmarkFolder implementation
  446. function BookmarkFolder(aId, aParent) {
  447.   this._id = aId;
  448.   this._parent = aParent;
  449.   this._annotations = new Annotations(this._id);
  450.   this._events = new Events();
  451.  
  452.   Utilities.bookmarks.addObserver(this, false);
  453.  
  454.   var self = this;
  455.   gShutdown.push(function() { self._shutdown(); });
  456. }
  457.  
  458. BookmarkFolder.prototype = {
  459.   _shutdown : function bmf_shutdown() {
  460.     this._annotations = null;
  461.     this._events = null;
  462.  
  463.     Utilities.bookmarks.removeObserver(this);
  464.   },
  465.  
  466.   get id() {
  467.     return this._id;
  468.   },
  469.  
  470.   get title() {
  471.     return Utilities.bookmarks.getItemTitle(this._id);
  472.   },
  473.  
  474.   set title(aTitle) {
  475.     Utilities.bookmarks.setItemTitle(this._id, aTitle);
  476.   },
  477.  
  478.   get description() {
  479.     return this._annotations.get("bookmarkProperties/description");
  480.   },
  481.  
  482.   set description(aDesc) {
  483.     this._annotations.set("bookmarkProperties/description", aDesc, Ci.nsIAnnotationService.EXPIRE_NEVER);
  484.   },
  485.  
  486.   get type() {
  487.     return "folder";
  488.   },
  489.  
  490.   get parent() {
  491.     return this._parent;
  492.   },
  493.  
  494.   set parent(aFolder) {
  495.     Utilities.bookmarks.moveItem(this._id, aFolder.id, Utilities.bookmarks.DEFAULT_INDEX);
  496.     // this._parent is updated in onItemMoved
  497.   },
  498.  
  499.   get annotations() {
  500.     return this._annotations;
  501.   },
  502.  
  503.   get events() {
  504.     return this._events;
  505.   },
  506.  
  507.   get children() {
  508.     var items = [];
  509.  
  510.     var options = Utilities.history.getNewQueryOptions();
  511.     var query = Utilities.history.getNewQuery();
  512.     query.setFolders([this._id], 1);
  513.     var result = Utilities.history.executeQuery(query, options);
  514.     var rootNode = result.root;
  515.     rootNode.containerOpen = true;
  516.     var cc = rootNode.childCount;
  517.     for (var i=0; i<cc; ++i) {
  518.       var node = rootNode.getChild(i);
  519.       if (node.type == node.RESULT_TYPE_FOLDER) {
  520.         var folder = new BookmarkFolder(node.itemId, this._id);
  521.         items.push(folder);
  522.       }
  523.       else if (node.type == node.RESULT_TYPE_SEPARATOR) {
  524.         var separator = new Bookmark(node.itemId, this._id, "separator");
  525.         items.push(separator);
  526.       }
  527.       else {
  528.         var bookmark = new Bookmark(node.itemId, this._id, "bookmark");
  529.         items.push(bookmark);
  530.       }
  531.     }
  532.     rootNode.containerOpen = false;
  533.  
  534.     return items;
  535.   },
  536.  
  537.   addBookmark : function bmf_addbm(aTitle, aUri) {
  538.     var newBookmarkID = Utilities.bookmarks.insertBookmark(this._id, aUri, Utilities.bookmarks.DEFAULT_INDEX, aTitle);
  539.     var newBookmark = new Bookmark(newBookmarkID, this, "bookmark");
  540.     return newBookmark;
  541.   },
  542.  
  543.   addSeparator : function bmf_addsep() {
  544.     var newBookmarkID = Utilities.bookmarks.insertSeparator(this._id, Utilities.bookmarks.DEFAULT_INDEX);
  545.     var newBookmark = new Bookmark(newBookmarkID, this, "separator");
  546.     return newBookmark;
  547.   },
  548.  
  549.   addFolder : function bmf_addfolder(aTitle) {
  550.     var newFolderID = Utilities.bookmarks.createFolder(this._id, aTitle, Utilities.bookmarks.DEFAULT_INDEX);
  551.     var newFolder = new BookmarkFolder(newFolderID, this);
  552.     return newFolder;
  553.   },
  554.  
  555.   remove : function bmf_remove() {
  556.     Utilities.bookmarks.removeFolder(this._id);
  557.   },
  558.  
  559.   // observer
  560.   onBeginUpdateBatch : function bmf_obub() {
  561.   },
  562.  
  563.   onEndUpdateBatch : function bmf_oeub() {
  564.   },
  565.  
  566.   onItemAdded : function bmf_oia(aId, aFolder, aIndex) {
  567.     // handle root folder events
  568.     if (!this._parent)
  569.       this._events.dispatch("add", aId);
  570.  
  571.     // handle this folder events
  572.     if (this._id == aFolder)
  573.       this._events.dispatch("addchild", aId);
  574.   },
  575.  
  576.   onItemRemoved : function bmf_oir(aId, aFolder, aIndex) {
  577.     // handle root folder events
  578.     if (!this._parent || this._id == aId)
  579.       this._events.dispatch("remove", aId);
  580.  
  581.     // handle this folder events
  582.     if (this._id == aFolder)
  583.       this._events.dispatch("removechild", aId);
  584.   },
  585.  
  586.   onItemChanged : function bmf_oic(aId, aProperty, aIsAnnotationProperty, aValue) {
  587.     // handle root folder and this folder events
  588.     if (!this._parent || this._id == aId)
  589.       this._events.dispatch("change", aProperty);
  590.   },
  591.  
  592.   onItemVisited: function bmf_oiv(aId, aVisitID, aTime) {
  593.   },
  594.  
  595.   onItemMoved: function bmf_oim(aId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
  596.     // handle this folder event, root folder cannot be moved
  597.     if (this._id == aId) {
  598.       this._parent = new BookmarkFolder(aNewParent, Utilities.bookmarks.getFolderIdForItem(aNewParent));
  599.       this._events.dispatch("move", aId);
  600.     }
  601.   },
  602.  
  603.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIBookmarkFolder, Ci.nsINavBookmarkObserver])
  604. };
  605.  
  606. //=================================================
  607. // BookmarkRoots implementation
  608. function BookmarkRoots() {
  609.   var self = this;
  610.   gShutdown.push(function() { self._shutdown(); });
  611. }
  612.  
  613. BookmarkRoots.prototype = {
  614.   _shutdown : function bmr_shutdown() {
  615.     this._menu = null;
  616.     this._toolbar = null;
  617.     this._tags = null;
  618.     this._unfiled = null;
  619.   },
  620.  
  621.   get menu() {
  622.     if (!this._menu)
  623.       this._menu = new BookmarkFolder(Utilities.bookmarks.bookmarksMenuFolder, null);
  624.  
  625.     return this._menu;
  626.   },
  627.  
  628.   get toolbar() {
  629.     if (!this._toolbar)
  630.       this._toolbar = new BookmarkFolder(Utilities.bookmarks.toolbarFolder, null);
  631.  
  632.     return this._toolbar;
  633.   },
  634.  
  635.   get tags() {
  636.     if (!this._tags)
  637.       this._tags = new BookmarkFolder(Utilities.bookmarks.tagsFolder, null);
  638.  
  639.     return this._tags;
  640.   },
  641.  
  642.   get unfiled() {
  643.     if (!this._unfiled)
  644.       this._unfiled = new BookmarkFolder(Utilities.bookmarks.unfiledBookmarksFolder, null);
  645.  
  646.     return this._unfiled;
  647.   },
  648.  
  649.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIBookmarkRoots])
  650. };
  651.  
  652.  
  653. //=================================================
  654. // Factory - Treat Application as a singleton
  655. // XXX This is required, because we're registered for the 'JavaScript global
  656. // privileged property' category, whose handler always calls createInstance.
  657. // See bug 386535.
  658. var gSingleton = null;
  659. var ApplicationFactory = {
  660.   createInstance: function af_ci(aOuter, aIID) {
  661.     if (aOuter != null)
  662.       throw Components.results.NS_ERROR_NO_AGGREGATION;
  663.  
  664.     if (gSingleton == null) {
  665.       gSingleton = new Application();
  666.     }
  667.  
  668.     return gSingleton.QueryInterface(aIID);
  669.   }
  670. };
  671.  
  672.  
  673.  
  674. //=================================================
  675. // Application constructor
  676. function Application() {
  677.   this.initToolkitHelpers();
  678.   this._bookmarks = null;
  679. }
  680.  
  681. //=================================================
  682. // Application implementation
  683. Application.prototype = {
  684.   // for nsIClassInfo + XPCOMUtils
  685.   classDescription: "Application",
  686.   classID:          Components.ID("fe74cf80-aa2d-11db-abbd-0800200c9a66"),
  687.   contractID:       "@mozilla.org/fuel/application;1",
  688.  
  689.   // redefine the default factory for XPCOMUtils
  690.   _xpcom_factory: ApplicationFactory,
  691.  
  692.   // for nsISupports
  693.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIApplication, Ci.extIApplication, Ci.nsIObserver, Ci.nsIClassInfo]),
  694.  
  695.   getInterfaces : function app_gi(aCount) {
  696.     var interfaces = [Ci.fuelIApplication, Ci.extIApplication, Ci.nsIObserver, Ci.nsIClassInfo];
  697.     aCount.value = interfaces.length;
  698.     return interfaces;
  699.   },
  700.  
  701.   // for nsIObserver
  702.   observe: function app_observe(aSubject, aTopic, aData) {
  703.     // Call the extApplication version of this function first
  704.     this.__proto__.__proto__.observe.call(this, aSubject, aTopic, aData);
  705.     if (aTopic == "xpcom-shutdown") {
  706.       this._bookmarks = null;
  707.       Utilities.free();
  708.     }
  709.   },
  710.  
  711.   get bookmarks() {
  712.     if (this._bookmarks == null)
  713.       this._bookmarks = new BookmarkRoots();
  714.  
  715.     return this._bookmarks;
  716.   },
  717.  
  718.   get windows() {
  719.     var win = [];
  720.     var enum = Utilities.windowMediator.getEnumerator("navigator:browser");
  721.  
  722.     while (enum.hasMoreElements())
  723.       win.push(new Window(enum.getNext()));
  724.  
  725.     return win;
  726.   },
  727.  
  728.   get activeWindow() {
  729.     return new Window(Utilities.windowMediator.getMostRecentWindow("navigator:browser"));
  730.   }
  731. };
  732.  
  733. //module initialization
  734. function NSGetModule(aCompMgr, aFileSpec) {
  735.   // set the proto, defined in extApplication.js
  736.   Application.prototype.__proto__ = extApplication.prototype;
  737.   return XPCOMUtils.generateModule([Application]);
  738. }
  739.  
  740. /* ***** BEGIN LICENSE BLOCK *****
  741.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  742.  *
  743.  * The contents of this file are subject to the Mozilla Public License Version
  744.  * 1.1 (the "License"); you may not use this file except in compliance with
  745.  * the License. You may obtain a copy of the License at
  746.  * http://www.mozilla.org/MPL/
  747.  *
  748.  * Software distributed under the License is distributed on an "AS IS" basis,
  749.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  750.  * for the specific language governing rights and limitations under the
  751.  * License.
  752.  *
  753.  * The Original Code is FUEL.
  754.  *
  755.  * The Initial Developer of the Original Code is Mozilla Corporation.
  756.  * Portions created by the Initial Developer are Copyright (C) 2006
  757.  * the Initial Developer. All Rights Reserved.
  758.  *
  759.  * Contributor(s):
  760.  *  Mark Finkle <mfinkle@mozilla.com> (Original Author)
  761.  *  John Resig  <jresig@mozilla.com> (Original Author)
  762.  *
  763.  * Alternatively, the contents of this file may be used under the terms of
  764.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  765.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  766.  * in which case the provisions of the GPL or the LGPL are applicable instead
  767.  * of those above. If you wish to allow use of your version of this file only
  768.  * under the terms of either the GPL or the LGPL, and not to allow others to
  769.  * use your version of this file under the terms of the MPL, indicate your
  770.  * decision by deleting the provisions above and replace them with the notice
  771.  * and other provisions required by the GPL or the LGPL. If you do not delete
  772.  * the provisions above, a recipient may use your version of this file under
  773.  * the terms of any one of the MPL, the GPL or the LGPL.
  774.  *
  775.  * ***** END LICENSE BLOCK ***** */
  776.  
  777. //=================================================
  778. // Shutdown - used to store cleanup functions which will
  779. //            be called on Application shutdown
  780. var gShutdown = [];
  781.  
  782. //=================================================
  783. // Console constructor
  784. function Console() {
  785.   this._console = Components.classes["@mozilla.org/consoleservice;1"]
  786.     .getService(Ci.nsIConsoleService);
  787. }
  788.  
  789. //=================================================
  790. // Console implementation
  791. Console.prototype = {
  792.   log : function cs_log(aMsg) {
  793.     this._console.logStringMessage(aMsg);
  794.   },
  795.  
  796.   open : function cs_open() {
  797.     var wMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  798.                               .getService(Ci.nsIWindowMediator);
  799.     var console = wMediator.getMostRecentWindow("global:console");
  800.     if (!console) {
  801.       var wWatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  802.                              .getService(Ci.nsIWindowWatcher);
  803.       wWatch.openWindow(null, "chrome://global/content/console.xul", "_blank",
  804.                         "chrome,dialog=no,all", null);
  805.     } else {
  806.       // console was already open
  807.       console.focus();
  808.     }
  809.   },
  810.  
  811.   QueryInterface : XPCOMUtils.generateQI([Ci.extIConsole])
  812. };
  813.  
  814.  
  815. //=================================================
  816. // EventItem constructor
  817. function EventItem(aType, aData) {
  818.   this._type = aType;
  819.   this._data = aData;
  820. }
  821.  
  822. //=================================================
  823. // EventItem implementation
  824. EventItem.prototype = {
  825.   _cancel : false,
  826.  
  827.   get type() {
  828.     return this._type;
  829.   },
  830.  
  831.   get data() {
  832.     return this._data;
  833.   },
  834.  
  835.   preventDefault : function ei_pd() {
  836.     this._cancel = true;
  837.   },
  838.  
  839.   QueryInterface : XPCOMUtils.generateQI([Ci.extIEventItem])
  840. };
  841.  
  842.  
  843. //=================================================
  844. // Events constructor
  845. function Events() {
  846.   this._listeners = [];
  847. }
  848.  
  849. //=================================================
  850. // Events implementation
  851. Events.prototype = {
  852.   addListener : function evts_al(aEvent, aListener) {
  853.     if (this._listeners.some(hasFilter))
  854.       return;
  855.  
  856.     this._listeners.push({
  857.       event: aEvent,
  858.       listener: aListener
  859.     });
  860.  
  861.     function hasFilter(element) {
  862.       return element.event == aEvent && element.listener == aListener;
  863.     }
  864.   },
  865.  
  866.   removeListener : function evts_rl(aEvent, aListener) {
  867.     this._listeners = this._listeners.filter(hasFilter);
  868.  
  869.     function hasFilter(element) {
  870.       return element.event != aEvent && element.listener != aListener;
  871.     }
  872.   },
  873.  
  874.   dispatch : function evts_dispatch(aEvent, aEventItem) {
  875.     eventItem = new EventItem(aEvent, aEventItem);
  876.  
  877.     this._listeners.forEach(function(key){
  878.       if (key.event == aEvent) {
  879.         key.listener.handleEvent ?
  880.           key.listener.handleEvent(eventItem) :
  881.           key.listener(eventItem);
  882.       }
  883.     });
  884.  
  885.     return !eventItem._cancel;
  886.   },
  887.  
  888.   QueryInterface : XPCOMUtils.generateQI([Ci.extIEvents])
  889. };
  890.  
  891.  
  892. //=================================================
  893. // PreferenceBranch constructor
  894. function PreferenceBranch(aBranch) {
  895.   if (!aBranch)
  896.     aBranch = "";
  897.  
  898.   this._root = aBranch;
  899.   this._prefs = Components.classes["@mozilla.org/preferences-service;1"]
  900.                           .getService(Ci.nsIPrefService);
  901.  
  902.   if (aBranch)
  903.     this._prefs = this._prefs.getBranch(aBranch);
  904.  
  905.   this._prefs.QueryInterface(Ci.nsIPrefBranch);
  906.   this._prefs.QueryInterface(Ci.nsIPrefBranch2);
  907.  
  908.   // we want to listen to "all" changes for this branch, so pass in a blank domain
  909.   this._prefs.addObserver("", this, true);
  910.   this._events = new Events();
  911.  
  912.   var self = this;
  913.   gShutdown.push(function() { self._shutdown(); });
  914. }
  915.  
  916. //=================================================
  917. // PreferenceBranch implementation
  918. PreferenceBranch.prototype = {
  919.   // cleanup observer so we don't leak
  920.   _shutdown: function prefs_shutdown() {
  921.     this._prefs.removeObserver(this._root, this);
  922.  
  923.     this._prefs = null;
  924.     this._events = null;
  925.   },
  926.  
  927.   // for nsIObserver
  928.   observe: function prefs_observe(aSubject, aTopic, aData) {
  929.     if (aTopic == "nsPref:changed")
  930.       this._events.dispatch("change", aData);
  931.   },
  932.  
  933.   get root() {
  934.     return this._root;
  935.   },
  936.  
  937.   get all() {
  938.     return this.find({});
  939.   },
  940.  
  941.   get events() {
  942.     return this._events;
  943.   },
  944.  
  945.   // XXX: Disabled until we can figure out the wrapped object issues
  946.   // name: "name" or /name/
  947.   // path: "foo.bar." or "" or /fo+\.bar/
  948.   // type: Boolean, Number, String (getPrefType)
  949.   // locked: true, false (prefIsLocked)
  950.   // modified: true, false (prefHasUserValue)
  951.   find : function prefs_find(aOptions) {
  952.     var retVal = [];
  953.     var items = this._prefs.getChildList("", []);
  954.  
  955.     for (var i = 0; i < items.length; i++) {
  956.       retVal.push(new Preference(items[i], this));
  957.     }
  958.  
  959.     return retVal;
  960.   },
  961.  
  962.   has : function prefs_has(aName) {
  963.     return (this._prefs.getPrefType(aName) != Ci.nsIPrefBranch.PREF_INVALID);
  964.   },
  965.  
  966.   get : function prefs_get(aName) {
  967.     return this.has(aName) ? new Preference(aName, this) : null;
  968.   },
  969.  
  970.   getValue : function prefs_gv(aName, aValue) {
  971.     var type = this._prefs.getPrefType(aName);
  972.  
  973.     switch (type) {
  974.       case Ci.nsIPrefBranch2.PREF_STRING:
  975.         aValue = this._prefs.getComplexValue(aName, Ci.nsISupportsString).data;
  976.         break;
  977.       case Ci.nsIPrefBranch2.PREF_BOOL:
  978.         aValue = this._prefs.getBoolPref(aName);
  979.         break;
  980.       case Ci.nsIPrefBranch2.PREF_INT:
  981.         aValue = this._prefs.getIntPref(aName);
  982.         break;
  983.     }
  984.  
  985.     return aValue;
  986.   },
  987.  
  988.   setValue : function prefs_sv(aName, aValue) {
  989.     var type = aValue != null ? aValue.constructor.name : "";
  990.  
  991.     switch (type) {
  992.       case "String":
  993.         var str = Components.classes["@mozilla.org/supports-string;1"]
  994.                             .createInstance(Ci.nsISupportsString);
  995.         str.data = aValue;
  996.         this._prefs.setComplexValue(aName, Ci.nsISupportsString, str);
  997.         break;
  998.       case "Boolean":
  999.         this._prefs.setBoolPref(aName, aValue);
  1000.         break;
  1001.       case "Number":
  1002.         this._prefs.setIntPref(aName, aValue);
  1003.         break;
  1004.       default:
  1005.         throw("Unknown preference value specified.");
  1006.     }
  1007.   },
  1008.  
  1009.   reset : function prefs_reset() {
  1010.     this._prefs.resetBranch("");
  1011.   },
  1012.  
  1013.   QueryInterface : XPCOMUtils.generateQI([Ci.extIPreferenceBranch, Ci.nsISupportsWeakReference])
  1014. };
  1015.  
  1016.  
  1017. //=================================================
  1018. // Preference constructor
  1019. function Preference(aName, aBranch) {
  1020.   this._name = aName;
  1021.   this._branch = aBranch;
  1022.   this._events = new Events();
  1023.  
  1024.   var self = this;
  1025.  
  1026.   this.branch.events.addListener("change", function(aEvent){
  1027.     if (aEvent.data == self.name)
  1028.       self.events.dispatch(aEvent.type, aEvent.data);
  1029.   });
  1030. }
  1031.  
  1032. //=================================================
  1033. // Preference implementation
  1034. Preference.prototype = {
  1035.   get name() {
  1036.     return this._name;
  1037.   },
  1038.  
  1039.   get type() {
  1040.     var value = "";
  1041.     var type = this.branch._prefs.getPrefType(this._name);
  1042.  
  1043.     switch (type) {
  1044.       case Ci.nsIPrefBranch2.PREF_STRING:
  1045.         value = "String";
  1046.         break;
  1047.       case Ci.nsIPrefBranch2.PREF_BOOL:
  1048.         value = "Boolean";
  1049.         break;
  1050.       case Ci.nsIPrefBranch2.PREF_INT:
  1051.         value = "Number";
  1052.         break;
  1053.     }
  1054.  
  1055.     return value;
  1056.   },
  1057.  
  1058.   get value() {
  1059.     return this.branch.getValue(this._name, null);
  1060.   },
  1061.  
  1062.   set value(aValue) {
  1063.     return this.branch.setValue(this._name, aValue);
  1064.   },
  1065.  
  1066.   get locked() {
  1067.     return this.branch._prefs.prefIsLocked(this.name);
  1068.   },
  1069.  
  1070.   set locked(aValue) {
  1071.     this.branch._prefs[ aValue ? "lockPref" : "unlockPref" ](this.name);
  1072.   },
  1073.  
  1074.   get modified() {
  1075.     return this.branch._prefs.prefHasUserValue(this.name);
  1076.   },
  1077.  
  1078.   get branch() {
  1079.     return this._branch;
  1080.   },
  1081.  
  1082.   get events() {
  1083.     return this._events;
  1084.   },
  1085.  
  1086.   reset : function pref_reset() {
  1087.     this.branch._prefs.clearUserPref(this.name);
  1088.   },
  1089.  
  1090.   QueryInterface : XPCOMUtils.generateQI([Ci.extIPreference])
  1091. };
  1092.  
  1093.  
  1094. //=================================================
  1095. // SessionStorage constructor
  1096. function SessionStorage() {
  1097.   this._storage = {};
  1098.   this._events = new Events();
  1099. }
  1100.  
  1101. //=================================================
  1102. // SessionStorage implementation
  1103. SessionStorage.prototype = {
  1104.   get events() {
  1105.     return this._events;
  1106.   },
  1107.  
  1108.   has : function ss_has(aName) {
  1109.     return this._storage.hasOwnProperty(aName);
  1110.   },
  1111.  
  1112.   set : function ss_set(aName, aValue) {
  1113.     this._storage[aName] = aValue;
  1114.     this._events.dispatch("change", aName);
  1115.   },
  1116.  
  1117.   get : function ss_get(aName, aDefaultValue) {
  1118.     return this.has(aName) ? this._storage[aName] : aDefaultValue;
  1119.   },
  1120.  
  1121.   QueryInterface : XPCOMUtils.generateQI([Ci.extISessionStorage])
  1122. };
  1123.  
  1124.  
  1125. //=================================================
  1126. // Extension constructor
  1127. function Extension(aItem) {
  1128.   this._item = aItem;
  1129.   this._firstRun = false;
  1130.   this._prefs = new PreferenceBranch("extensions." + this._item.id + ".");
  1131.   this._storage = new SessionStorage();
  1132.   this._events = new Events();
  1133.  
  1134.   var installPref = "install-event-fired";
  1135.   if (!this._prefs.has(installPref)) {
  1136.     this._prefs.setValue(installPref, true);
  1137.     this._firstRun = true;
  1138.   }
  1139.  
  1140.   this._enabled = false;
  1141.   const PREFIX_ITEM_URI = "urn:mozilla:item:";
  1142.   const PREFIX_NS_EM = "http://www.mozilla.org/2004/em-rdf#";
  1143.   var rdf = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
  1144.   var itemResource = rdf.GetResource(PREFIX_ITEM_URI + this._item.id);
  1145.   if (itemResource) {
  1146.     var extmgr = Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager);
  1147.     var ds = extmgr.datasource;
  1148.     var target = ds.GetTarget(itemResource, rdf.GetResource(PREFIX_NS_EM + "isDisabled"), true);
  1149.     if (target && target instanceof Ci.nsIRDFLiteral)
  1150.       this._enabled = (target.Value != "true");
  1151.   }
  1152.  
  1153.   var os = Components.classes["@mozilla.org/observer-service;1"]
  1154.                      .getService(Ci.nsIObserverService);
  1155.   os.addObserver(this, "em-action-requested", false);
  1156.  
  1157.   var self = this;
  1158.   gShutdown.push(function(){ self._shutdown(); });
  1159. }
  1160.  
  1161. //=================================================
  1162. // Extension implementation
  1163. Extension.prototype = {
  1164.   // cleanup observer so we don't leak
  1165.   _shutdown: function ext_shutdown() {
  1166.     var os = Components.classes["@mozilla.org/observer-service;1"]
  1167.                        .getService(Ci.nsIObserverService);
  1168.     os.removeObserver(this, "em-action-requested");
  1169.  
  1170.     this._prefs = null;
  1171.     this._storage = null;
  1172.     this._events = null;
  1173.   },
  1174.  
  1175.   // for nsIObserver
  1176.   observe: function ext_observe(aSubject, aTopic, aData)
  1177.   {
  1178.     if ((aSubject instanceof Ci.nsIUpdateItem) && (aSubject.id == this._item.id))
  1179.     {
  1180.       if (aData == "item-uninstalled")
  1181.         this._events.dispatch("uninstall", this._item.id);
  1182.       else if (aData == "item-disabled")
  1183.         this._events.dispatch("disable", this._item.id);
  1184.       else if (aData == "item-enabled")
  1185.         this._events.dispatch("enable", this._item.id);
  1186.       else if (aData == "item-cancel-action")
  1187.         this._events.dispatch("cancel", this._item.id);
  1188.       else if (aData == "item-upgraded")
  1189.         this._events.dispatch("upgrade", this._item.id);
  1190.     }
  1191.   },
  1192.  
  1193.   get id() {
  1194.     return this._item.id;
  1195.   },
  1196.  
  1197.   get name() {
  1198.     return this._item.name;
  1199.   },
  1200.  
  1201.   get enabled() {
  1202.     return this._enabled;
  1203.   },
  1204.  
  1205.   get version() {
  1206.     return this._item.version;
  1207.   },
  1208.  
  1209.   get firstRun() {
  1210.     return this._firstRun;
  1211.   },
  1212.  
  1213.   get storage() {
  1214.     return this._storage;
  1215.   },
  1216.  
  1217.   get prefs() {
  1218.     return this._prefs;
  1219.   },
  1220.  
  1221.   get events() {
  1222.     return this._events;
  1223.   },
  1224.  
  1225.   QueryInterface : XPCOMUtils.generateQI([Ci.extIExtension])
  1226. };
  1227.  
  1228.  
  1229. //=================================================
  1230. // Extensions constructor
  1231. function Extensions() {
  1232.   this._extmgr = Components.classes["@mozilla.org/extensions/manager;1"]
  1233.                            .getService(Ci.nsIExtensionManager);
  1234.  
  1235.   this._cache = {};
  1236.  
  1237.   var self = this;
  1238.   gShutdown.push(function() { self._shutdown(); });
  1239. }
  1240.  
  1241. //=================================================
  1242. // Extensions implementation
  1243. Extensions.prototype = {
  1244.   _shutdown : function exts_shutdown() {
  1245.     this._extmgr = null;
  1246.     this._cache = null;
  1247.   },
  1248.  
  1249.   /*
  1250.    * Helper method to check cache before creating a new extension
  1251.    */
  1252.   _get : function exts_get(aId) {
  1253.     if (this._cache.hasOwnProperty(aId))
  1254.       return this._cache[aId];
  1255.  
  1256.     var newExt = new Extension(this._extmgr.getItemForID(aId));
  1257.     this._cache[aId] = newExt;
  1258.     return newExt;
  1259.   },
  1260.  
  1261.   get all() {
  1262.     return this.find({});
  1263.   },
  1264.  
  1265.   // XXX: Disabled until we can figure out the wrapped object issues
  1266.   // id: "some@id" or /id/
  1267.   // name: "name" or /name/
  1268.   // version: "1.0.1"
  1269.   // minVersion: "1.0"
  1270.   // maxVersion: "2.0"
  1271.   find : function exts_find(aOptions) {
  1272.     var retVal = [];
  1273.     var items = this._extmgr.getItemList(Ci.nsIUpdateItem.TYPE_EXTENSION, {});
  1274.  
  1275.     for (var i = 0; i < items.length; i++) {
  1276.       retVal.push(this._get(items[i].id));
  1277.     }
  1278.  
  1279.     return retVal;
  1280.   },
  1281.  
  1282.   has : function exts_has(aId) {
  1283.     return this._extmgr.getItemForID(aId) != null;
  1284.   },
  1285.  
  1286.   get : function exts_get(aId) {
  1287.     return this.has(aId) ? this._get(aId) : null;
  1288.   },
  1289.  
  1290.   QueryInterface : XPCOMUtils.generateQI([Ci.extIExtensions])
  1291. };
  1292.  
  1293. //=================================================
  1294. // extApplication constructor
  1295. function extApplication() {
  1296. }
  1297.  
  1298. //=================================================
  1299. // extApplication implementation
  1300. extApplication.prototype = {
  1301.   initToolkitHelpers: function extApp_initToolkitHelpers() {
  1302.     this._console = null;
  1303.     this._storage = null;
  1304.     this._prefs = null;
  1305.     this._extensions = null;
  1306.     this._events = null;
  1307.  
  1308.     this._info = Components.classes["@mozilla.org/xre/app-info;1"]
  1309.                            .getService(Ci.nsIXULAppInfo);
  1310.  
  1311.     var os = Components.classes["@mozilla.org/observer-service;1"]
  1312.                        .getService(Ci.nsIObserverService);
  1313.  
  1314.     os.addObserver(this, "final-ui-startup", false);
  1315.     os.addObserver(this, "quit-application-requested", false);
  1316.     os.addObserver(this, "xpcom-shutdown", false);
  1317.   },
  1318.  
  1319.   // get this contractID registered for certain categories via XPCOMUtils
  1320.   _xpcom_categories: [
  1321.     // make Application a startup observer
  1322.     { category: "app-startup", service: true },
  1323.  
  1324.     // add Application as a global property for easy access
  1325.     { category: "JavaScript global privileged property" }
  1326.   ],
  1327.  
  1328.   // for nsIClassInfo
  1329.   flags : Ci.nsIClassInfo.SINGLETON,
  1330.   implementationLanguage : Ci.nsIProgrammingLanguage.JAVASCRIPT,
  1331.  
  1332.   getInterfaces : function app_gi(aCount) {
  1333.     var interfaces = [Ci.extIApplication, Ci.nsIObserver, Ci.nsIClassInfo];
  1334.     aCount.value = interfaces.length;
  1335.     return interfaces;
  1336.   },
  1337.  
  1338.   getHelperForLanguage : function app_ghfl(aCount) {
  1339.     return null;
  1340.   },
  1341.  
  1342.   // extIApplication
  1343.   get id() {
  1344.     return this._info.ID;
  1345.   },
  1346.  
  1347.   get name() {
  1348.     return this._info.name;
  1349.   },
  1350.  
  1351.   get version() {
  1352.     return this._info.version;
  1353.   },
  1354.  
  1355.   // for nsIObserver
  1356.   observe: function app_observe(aSubject, aTopic, aData) {
  1357.     if (aTopic == "app-startup") {
  1358.       this._extensions = new Extensions();
  1359.       this.events.dispatch("load", "application");
  1360.     }
  1361.     else if (aTopic == "final-ui-startup") {
  1362.       this.events.dispatch("ready", "application");
  1363.     }
  1364.     else if (aTopic == "quit-application-requested") {
  1365.       // we can stop the quit by checking the return value
  1366.       if (this.events.dispatch("quit", "application") == false)
  1367.         aSubject.data = true;
  1368.     }
  1369.     else if (aTopic == "xpcom-shutdown") {
  1370.  
  1371.       this.events.dispatch("unload", "application");
  1372.  
  1373.       // call the cleanup functions and empty the array
  1374.       while (gShutdown.length) {
  1375.         gShutdown.shift()();
  1376.       }
  1377.  
  1378.       // release our observers
  1379.       var os = Components.classes["@mozilla.org/observer-service;1"]
  1380.                          .getService(Ci.nsIObserverService);
  1381.  
  1382.       os.removeObserver(this, "final-ui-startup");
  1383.       os.removeObserver(this, "quit-application-requested");
  1384.       os.removeObserver(this, "xpcom-shutdown");
  1385.  
  1386.       this._info = null;
  1387.       this._console = null;
  1388.       this._prefs = null;
  1389.       this._storage = null;
  1390.       this._events = null;
  1391.       this._extensions = null;
  1392.     }
  1393.   },
  1394.  
  1395.   get console() {
  1396.     if (this._console == null)
  1397.         this._console = new Console();
  1398.  
  1399.     return this._console;
  1400.   },
  1401.  
  1402.   get storage() {
  1403.     if (this._storage == null)
  1404.         this._storage = new SessionStorage();
  1405.  
  1406.     return this._storage;
  1407.   },
  1408.  
  1409.   get prefs() {
  1410.     if (this._prefs == null)
  1411.         this._prefs = new PreferenceBranch("");
  1412.  
  1413.     return this._prefs;
  1414.   },
  1415.  
  1416.   get extensions() {
  1417.     return this._extensions;
  1418.   },
  1419.  
  1420.   get events() {
  1421.     if (this._events == null)
  1422.         this._events = new Events();
  1423.  
  1424.     return this._events;
  1425.   },
  1426.  
  1427.   QueryInterface : XPCOMUtils.generateQI([Ci.extIApplication, Ci.nsISupportsWeakReference])
  1428. };
  1429.