home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 398 / 398.xpi / components / nsForecastfox.js next >
Encoding:
Text File  |  2010-02-04  |  34.8 KB  |  1,106 lines

  1. /*------------------------------------------------------------------------------
  2.   Copyright (c) 2008 Ensolis, LLC. All Rights Reserved.
  3.   ----------------------------------------------------------------------------*/
  4.  
  5. /*------------------------------------------------------------------------------
  6.   Copyright (c) 2008 Ensolis, LLC. All Rights Reserved.
  7.   ----------------------------------------------------------------------------*/
  8.   
  9. /******************************************************************************
  10.  * WARNING!!! This file cannot be used from the main overlay (forecastfox.js).
  11.  *            There are variables and functions that conflict with browser 
  12.  *            code and could potentially conflict with other extensions.
  13.  *****************************************************************************/ 
  14.  
  15. /******************************************************************************
  16.  * Component Constants
  17.  *****************************************************************************/ 
  18. const Cc = Components.classes;
  19. const Ci = Components.interfaces;
  20. const Cr = Components.results;
  21.  
  22. /******************************************************************************
  23.  * File Permission Constants
  24.  *****************************************************************************/ 
  25. /*jsl:ignore*/
  26. const PERMS_FILE = 0644;
  27. const PERMS_DIRECTORY = 0755;
  28. /*jsl:end*/
  29.  
  30. /******************************************************************************
  31.  * File Type Constants
  32.  *****************************************************************************/
  33. const TYPE_PROFILE = Ci.ffIDiskService.TYPE_PROFILE;
  34. const TYPE_CACHE = Ci.ffIDiskService.TYPE_CACHE;
  35. const TYPE_ICONS = Ci.ffIDiskService.TYPE_ICONS;
  36. const TYPE_TEMP = Ci.ffIDiskService.TYPE_TEMP;
  37. const TYPE_DEFAULTS = Ci.ffIDiskService.TYPE_DEFAULTS;
  38. const TYPE_WEATHERFOX = Ci.ffIDiskService.TYPE_WEATHERFOX;
  39. const TYPE_ERRORS = Ci.ffIDiskService.TYPE_ERRORS;
  40.  
  41. /******************************************************************************
  42.  * Severity Constants
  43.  *****************************************************************************/
  44. const SEVERITY_INFO = Ci.ffIErrorItem.SEVERITY_INFO;
  45. const SEVERITY_WARNING = Ci.ffIErrorItem.SEVERITY_WARNING;
  46. const SEVERITY_ERROR = Ci.ffIErrorItem.SEVERITY_ERROR;
  47.  
  48. const ONE_SECOND = 1000;
  49. const ONE_MINUTE = 60*ONE_SECOND;
  50. const ONE_HOUR = 60*ONE_MINUTE;
  51. const ONE_DAY = 24*ONE_HOUR;
  52. const ONE_WEEK = 7*ONE_DAY;
  53. const ONE_MONTH = 4*ONE_WEEK;
  54.  
  55. /******************************************************************************
  56.  * Preferences Excluded from Profiles Constant
  57.  *****************************************************************************/
  58. const EXCLUDED_PREFS = {
  59.   "migrated": true,
  60.   "migrated.prefs": true,
  61.   "pinged": true,
  62.   "icons.version": true,
  63.   "icons.uninstallfiles": true,
  64.   "onetime.chromepromo": true,
  65.   "profile.current": true,
  66.   "profile.switch.delay": true,
  67.   "profile.switch.enabled": true,      
  68.   "links.alert": true,
  69.   "links.dialog": true,
  70.   "links.panel": true,
  71.   "links.context": true,
  72.   "pinged.daily": true,
  73.   "pinged.weekly": true,
  74.   "pinged.monthly": true,
  75.   "debug": true
  76. };
  77.  
  78. /******************************************************************************
  79.  * DTD and Namespace Constants for Import, Export, and Profiles.xml
  80.  *****************************************************************************/
  81. const PROFILES_DTD = "http://forecastfox.ensolis.com/specs/1.0/profiles.dtd";
  82. const PROFILES_NS = "http://forecastfox.ensolis.com/specs/1.0/profiles";
  83.  
  84. /******************************************************************************
  85.  * Gets a preference branch.  
  86.  *
  87.  * @param   Boolean if getting the default branch or current branch.
  88.  * @param   Name of the branch to get.  If null is passed then "forecastfox."
  89.  *          is the branch retrieved.
  90.  * @return  Requested preference branch.
  91.  *****************************************************************************/
  92. function getBranch(aDefault, aName)
  93. {
  94.   //forecastf pref branch
  95.   const FF_NAME = "forecastfox.";
  96.   
  97.   //get pref service
  98.   var pbSvc = Cc["@mozilla.org/preferences-service;1"].
  99.               getService(Ci.nsIPrefService);
  100.   
  101.   //get the default branch
  102.   if (aDefault)
  103.     return (aName) ? pbSvc.getDefaultBranch(aName) : 
  104.                      pbSvc.getDefaultBranch(FF_NAME);
  105.   
  106.   //get the specified branch
  107.   return (aName) ? pbSvc.getBranch(aName) : 
  108.                    pbSvc.getBranch(FF_NAME);
  109. }
  110.  
  111. /******************************************************************************
  112.  * Gets a preference.  
  113.  *
  114.  * @param   Name of the preference to retrieve.
  115.  * @return  Requested preference value. 
  116.  *****************************************************************************/
  117. var gHelpersBranch = null;
  118. function getPref(aName)
  119. {
  120.   //get pref branch
  121.   if (!gHelpersBranch)
  122.     gHelpersBranch = getBranch(false, null);
  123.   var branch = gHelpersBranch;
  124.   
  125.   //return value based on pref type
  126.   var rv = "";
  127.   switch (branch.getPrefType(aName)) {
  128.   case Ci.nsIPrefBranch.PREF_INT:
  129.     rv = branch.getIntPref(aName);
  130.     break;
  131.   case Ci.nsIPrefBranch.PREF_BOOL:
  132.     rv = branch.getBoolPref(aName);
  133.     break;
  134.   case Ci.nsIPrefBranch.PREF_STRING:
  135.   default:
  136.     try {
  137.       rv = branch.getComplexValue(aName, Ci.nsIPrefLocalizedString).data;                         
  138.     } catch(e) {
  139.       try {
  140.         rv = branch.getComplexValue(aName, Ci.nsISupportsString).data;
  141.       } catch(e) {
  142.         rv = branch.getCharPref(aName); 
  143.       }
  144.     }
  145.     break;    
  146.   }
  147.   return rv; 
  148. }
  149.  
  150. /******************************************************************************
  151.  * Sets a preference.  
  152.  *
  153.  * @param   Name of the preference to retrieve.
  154.  * @param   Value to set the preference to.
  155.  *****************************************************************************/
  156. function setPref(aName, aValue)
  157. {
  158.   //get pref branch
  159.   if (!gHelpersBranch)
  160.     gHelpersBranch = getBranch(false, null);
  161.   var branch = gHelpersBranch;
  162.   
  163.   //do nothing if value is unchanged
  164.   var oldValue = getPref(aName);
  165.   if (aValue == oldValue)
  166.     return;
  167.   
  168.   //remove user value if same as the default
  169.   var restored = restorePref(aName, aValue);
  170.   if (restored)
  171.     return;
  172.     
  173.   //set value based on pref type
  174.   switch (branch.getPrefType(aName)) {
  175.   case Ci.nsIPrefBranch.PREF_INT:
  176.     branch.setIntPref(aName, aValue);
  177.     break;
  178.   case Ci.nsIPrefBranch.PREF_BOOL:
  179.      branch.setBoolPref(aName, aValue);
  180.      break;
  181.   case Ci.nsIPrefBranch.PREF_STRING:
  182.   default:
  183.     try {
  184.       var plString = Cc["@mozilla.org/pref-localizedstring;1"].
  185.                      createInstance(Ci.nsIPrefLocalizedString);    
  186.       plString.data = aValue;
  187.       branch.setComplexValue(aName, Ci.nsIPrefLocalizedString, plString);
  188.     } catch(e) {
  189.       try {
  190.         var sString = Cc["@mozilla.org/supports-string;1"].
  191.                       createInstance(Ci.nsISupportsString);    
  192.         sString.data = aValue;
  193.         branch.setComplexValue(aName, Ci.nsISupportsString, sString);
  194.       } catch(e) {
  195.         branch.setCharPref(aName, aValue);
  196.       }
  197.     }
  198.     break;                         
  199.   }   
  200. }
  201.  
  202. /******************************************************************************
  203.  * Restores a default preference.  
  204.  *
  205.  * @param   Name of the preference to retrieve.
  206.  * @param   The new value of the preference.
  207.  * @return  True if pref was restored 
  208.  *****************************************************************************/
  209. function restorePref(aName, aValue)
  210. {
  211.   //get pref branch
  212.   var branch = getBranch(true, null);
  213.   
  214.   //get value based on pref type
  215.   try {
  216.     var defaultValue = "";
  217.     switch (branch.getPrefType(aName)) {
  218.     case Ci.nsIPrefBranch.PREF_INT:
  219.       defaultValue = branch.getIntPref(aName);
  220.       break;
  221.     case Ci.nsIPrefBranch.PREF_BOOL:
  222.       defaultValue = branch.getBoolPref(aName);
  223.       break;
  224.     case Ci.nsIPrefBranch.PREF_STRING:
  225.     default:
  226.       try {
  227.         defaultValue = branch.getComplexValue(aName, Ci.nsIPrefLocalizedString).data;                         
  228.       } catch(e) {
  229.         try {
  230.           defaultValue = branch.getComplexValue(aName, Ci.nsISupportsString).data;
  231.         } catch(e) {
  232.           defaultValue = branch.getCharPref(aName); 
  233.         }
  234.       }
  235.       break;    
  236.     }
  237.   } catch(e) {
  238.     return false;
  239.   }
  240.   
  241.   //value is the same do not restore
  242.   if (aValue != defaultValue)
  243.     return false;
  244.   
  245.   //get pref branch
  246.   if (!gHelpersBranch)
  247.     gHelpersBranch = getBranch(false, null);
  248.   branch = gHelpersBranch;
  249.   
  250.   //clear the value
  251.   try {
  252.     branch.clearUserPref(aName); 
  253.   } catch(e) {
  254.     return false;
  255.   }
  256.   
  257.   // preference was cleared
  258.   return true;
  259. }
  260.  
  261. /******************************************************************************
  262.  * removes the specified file
  263.  * 
  264.  * @param     File to remove.  If file is a directory all files within the 
  265.  *            directory will be removed.
  266.  *****************************************************************************/
  267. function removeFile(aFile)
  268. {
  269.   if (aFile.isDirectory())
  270.     aFile.remove(true);
  271.   else
  272.     aFile.remove(false);
  273. }
  274.  
  275. /******************************************************************************
  276.  * Gets a directory based on a special directory key.  
  277.  *
  278.  * @param   Special directory key.
  279.  * @param   Array of sub directories from the special directory.
  280.  * @param   Create the sub directory if it doesn't exist.
  281.  * @return  A nsIFile interface for the requested file.
  282.  *****************************************************************************/
  283. function getKeyedDirectory(aKey, aPathArray, aCreate)
  284. {
  285.   //get directory service
  286.   var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
  287.                getService(Ci.nsIProperties);
  288.   
  289.   //get base directory             
  290.   var dir = dirSvc.get(aKey, Ci.nsIFile);
  291.   
  292.   //loop through path array
  293.   for (var i=0; i<aPathArray.length; i++) {      
  294.     dir.append(aPathArray[i]);
  295.     
  296.     //create directory if instructed
  297.     if (aCreate && !dir.exists())
  298.       dir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
  299.   }
  300.  
  301.   return dir;
  302. }
  303.  
  304. /******************************************************************************
  305.  * Gets a directory from the installed directory.  
  306.  *
  307.  * @param   Array of sub directories from the install directory.
  308.  * @return  A nsIFile interface for the requested file.
  309.  *****************************************************************************/
  310. function getInstallDirectory(aPathArray)
  311. {
  312.   //setup objects
  313.   var dir = null;
  314.   
  315.   //get extension manager - toolkit 1.0 or greater
  316.   if ("@mozilla.org/extensions/manager;1" in Cc) {
  317.     var em = Cc["@mozilla.org/extensions/manager;1"].
  318.              getService(Ci.nsIExtensionManager);
  319.              
  320.     //get install location from extension manager - toolkit 1.5            
  321.     if ("nsIInstallLocation" in Ci) {
  322.       dir = em.getInstallLocation("{0538E3E3-7E9B-4d49-8831-A227C80A7AD3}");
  323.       dir = dir.getItemLocation("{0538E3E3-7E9B-4d49-8831-A227C80A7AD3}");
  324.     }   
  325.   }
  326.     
  327.   //couldn't use extension manager so try the profile directory - non toolkit
  328.   if (!dir) {
  329.     var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
  330.                  getService(Ci.nsIProperties);      
  331.     dir = dirSvc.get("ProfD", Ci.nsIFile);
  332.     dir.append("extensions");
  333.     dir.append("{0538E3E3-7E9B-4d49-8831-A227C80A7AD3}");
  334.     
  335.     //not in the profile directory so it must be in the app directory
  336.     if (!dir.exists()) {
  337.       dir = dirSvc.get("XCurProcD", Ci.nsIFile); 
  338.       dir.append("extensions");
  339.       dir.append("{0538E3E3-7E9B-4d49-8831-A227C80A7AD3}");
  340.     }      
  341.   }
  342.   
  343.   //loop through path array
  344.   for (var i=0; i<aPathArray.length; i++)
  345.     dir.append(aPathArray[i]);
  346.  
  347.   return dir;
  348. }
  349.    
  350. /******************************************************************************
  351.  * Get the top most open window.  A window has to open for this to be called.
  352.  * Use this if the type of window does not matter.
  353.  * 
  354.  * @return  A window object used for modality.
  355.  *****************************************************************************/
  356. function getTopWindow()
  357. {
  358.   //get top window
  359.   var mediator = Cc["@mozilla.org/appshell/window-mediator;1"].
  360.                  getService(Ci.nsIWindowMediator);
  361.   return mediator.getMostRecentWindow(null); 
  362. }
  363.    
  364. /******************************************************************************
  365.  * Get the main application window.  Use this if the type of window does matter.
  366.  * 
  367.  * @return  A window object used for modality.
  368.  *****************************************************************************/
  369. function getMainWindow()
  370. {
  371.   /** this may need to change if main window of a 
  372.       supported app is not "navigator:browser" **/
  373.   
  374.   //get the mediator service
  375.   var mediator = Cc["@mozilla.org/appshell/window-mediator;1"].
  376.                  getService(Ci.nsIWindowMediator);
  377.   
  378.   //get the app window
  379.   var main = mediator.getMostRecentWindow("navigator:browser");
  380.   if (main)
  381.     return main;
  382.                        
  383.   //get the watcher service
  384.   var watcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].
  385.                 getService(Ci.nsIWindowWatcher);                 
  386.  
  387.   //open a new window    
  388.   main = watcher.openWindow(null, "chrome://browser/content/browser.xul", 
  389.                             "_blank", "chrome,all,dialog=no", "about:blank"); 
  390.   return main;
  391. }
  392.      
  393. /******************************************************************************
  394.  * String enumerator of hash table keys.
  395.  * 
  396.  * @param   Javascript hash table. 
  397.  * @return  A nsIStringEnumerator of the keys.
  398.  *****************************************************************************/
  399. function KeyEnumerator(aHashTable)
  400. {
  401.   //setup key array
  402.   this._keys = [];
  403.   this._index = 0;
  404.   
  405.   //load with data
  406.   if (aHashTable) {
  407.     for (var name in aHashTable)
  408.       this._keys.push(name);
  409.   }
  410. }
  411. KeyEnumerator.prototype = {
  412.   _index: null,
  413.   _keys: null,
  414.   
  415.   QueryInterface: function KeyEnumerator_QueryInterface(aIID)
  416.   {
  417.     if (!aIID.equals(Ci.nsIStringEnumerator) ||
  418.         !aIID.equals(Ci.nsISupports))
  419.       throw Cr.NS_ERROR_NO_INTERFACE; 
  420.     return this;   
  421.   },
  422.   
  423.   hasMore: function KeyEnumerator_hasMore()
  424.   {
  425.     return this._index < this._keys.length;
  426.   },
  427.   
  428.   getNext: function KeyEnumerator_getNext()
  429.   {
  430.     var rv = this._keys[this._index];
  431.     this._index++; 
  432.     return rv;
  433.   }
  434. };
  435.  
  436. /******************************************************************************
  437.  * Sorts an array ascending where the items have a name property. 
  438.  *
  439.  * @param   Current array item.
  440.  * @param   Next array item.
  441.  *
  442.  * @return  1 if greater, 0 if equal, and -1 if less than. 
  443.  *****************************************************************************/
  444. function sortByName(aItem1, aItem2)
  445. {
  446.   if (aItem1.name < aItem2.name)
  447.     return -1;
  448.   else if (aItem1.name == aItem2.name)
  449.     return 0;
  450.  
  451.   return 1;
  452. }
  453.  
  454. /******************************************************************************
  455.  * Get a new prompter.
  456.  *
  457.  * @param   The parent window for the prompter can be null.
  458.  *
  459.  * @return  A new prompter. 
  460.  *****************************************************************************/
  461. function getPrompter(aParent)
  462. {
  463.   //get the watcher service
  464.   var watcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].
  465.                 getService(Ci.nsIWindowWatcher);
  466.                 
  467.   //return a prompter
  468.   return watcher.getNewPrompter(aParent);
  469. }
  470.  
  471. /******************************************************************************
  472.  * Gets the forecastfox string bundle.
  473.  *
  474.  * @return  A nsIStringBundle interface for the requested url.
  475.  *****************************************************************************/
  476. var gHelpersBundle = null;
  477. function getBundle()
  478. {
  479.   if (gHelpersBundle != null)
  480.     return gHelpersBundle;
  481.     
  482.   const BUNDLE_URL = "chrome://forecastfox/locale/forecastfox.properties";
  483.  
  484.   //get the stringbundle service
  485.   var sbSvc = Cc["@mozilla.org/intl/stringbundle;1"].
  486.               getService(Ci.nsIStringBundleService); 
  487.   
  488.   //get the bundle and return it  
  489.   gHelpersBundle = sbSvc.createBundle(BUNDLE_URL);       
  490.   return gHelpersBundle;
  491. }
  492.  
  493. /******************************************************************************
  494.  * Checks if the alert service is included.
  495.  *
  496.  * @return  True if alert service is present. 
  497.  *****************************************************************************/
  498. var gHelpersHasAlert = null;
  499. function checkAlertService()
  500. {
  501.   //return cached alert check
  502.   if (gHelpersHasAlert != null) 
  503.     return gHelpersHasAlert;
  504.  
  505.   //check if the alert interface exists
  506.   if ("nsIAlertsService" in Ci)
  507.     gHelpersHasAlert = true;
  508.   else
  509.     gHelpersHasAlert = false;
  510.     
  511.   //cache the flag and return the value
  512.   return gHelpersHasAlert;
  513. }
  514.  
  515. /******************************************************************************
  516.  * Open a link in the main application window
  517.  *
  518.  * @param   The url to open.
  519.  * @param   Where to open the link (current, window, tab, tabshifted)
  520.  *****************************************************************************/ 
  521. function openLink(aURL, aWhere)
  522. {
  523.   var win = getMainWindow();
  524.   var browser = win.document.getElementById("content");
  525.   var features = "chrome,all,dialog=no";
  526.   var chrome = "";
  527.   switch (aWhere) {
  528.   
  529.   //open in a new window
  530.   case "window":
  531.     chrome = "chrome://browser/content/browser.xul";    
  532.     win.openDialog(chrome, "_blank", features, aURL, null, null);
  533.     break;
  534.     
  535.   //open in a new tab
  536.   case "tab":
  537.   case "tabshifted":
  538.     var tab = browser.addTab(aURL);
  539.     
  540.     //focus the tab
  541.     if (aWhere == "tab") {
  542.       browser.selectedTab = tab;
  543.       win.content.focus();
  544.     }        
  545.     break;
  546.     
  547.   //open in the current tab
  548.   case "current":
  549.   default: 
  550.     browser.loadURI(aURL);
  551.     win.content.focus();
  552.     break;
  553.   }
  554. }
  555.  
  556. /******************************************************************************
  557.  * write a message to the console and to stdout
  558.  *
  559.  * @param   Values to log.
  560.  *****************************************************************************/  
  561. function LOG(values) {
  562.   var debug = getPref("debug");
  563.   if (debug === true) {
  564.     var msg =(values.join ? values.join("") : values);
  565.     console = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
  566.     console.logStringMessage(msg);
  567.     dump(msg + "\n");
  568.   }
  569. }
  570.  
  571. /******************************************************************************
  572.  * Generic item constructor used by different item components as
  573.  * a prototype for the component.
  574.  *
  575.  * @param     Component name.
  576.  ******************************************************************************/
  577. function ItemBase(aName)
  578. {
  579.   this._name = aName;
  580.   this._ifaces = [this.interfaceID, Ci.ffIItem, 
  581.                   Ci.nsIClassInfo, Ci.nsISupports];
  582. }
  583. ItemBase.prototype = {
  584.   _name: null,
  585.   _ifaces: null,
  586.      
  587.   ////////////////////////////////
  588.   // nsISupports
  589.   QueryInterface: function ItemBase_QueryInterface(aIID)
  590.   {
  591.     var ifaces = this.getInterfaces({});
  592.     for (var i=0; i<ifaces.length; i++) {
  593.       if (aIID.equals(ifaces[i]))
  594.         return this;
  595.     }
  596.  
  597.     throw Cr.NS_ERROR_NO_INTERFACE;
  598.   },
  599.             
  600.   ////////////////////////////////
  601.   // nsIClassInfo
  602.   getInterfaces: function ItemBase_getInterfaces(aCount)
  603.   {
  604.     aCount.value = this._ifaces.length;
  605.     return this._ifaces;
  606.   },
  607.   
  608.   getHelperForLanguage: function ItemBase_getHelperForLanguage(aLanguage) { return null; },
  609.   get contractID() { return gComponents[this._name].contractID; },
  610.   get classID() { return gComponents[this._name].classID; },
  611.   get classDescription() { return gComponents[this._name].className; },
  612.   get implementationLanguage() { return Ci.nsIProgrammingLanguage.JAVASCRIPT; },
  613.   get flags() { return Ci.nsIClassInfo.MAIN_THREAD_ONLY; },
  614.             
  615.   ////////////////////////////////
  616.   // ffIItem
  617.     
  618.   /**
  619.    * Unique ID of the item.
  620.    */ 
  621.   get ID() { return this.getProperty("ID"); },
  622.     
  623.   /**
  624.    * String enumerator of property names.
  625.    * 
  626.    */
  627.    get properties() { return new KeyEnumerator(this._properties); },
  628.     
  629.   /**
  630.    * Check if a given property is present in the item.
  631.    * 
  632.    * @param   Name of the property to check.
  633.    * @return  True if present, false if absent.
  634.    */
  635.   hasProperty: function ItemBase_hasProperty(aName)
  636.   {
  637.     return this._properties.hasOwnProperty(aName);
  638.   },
  639.                     
  640.   /**
  641.    * Retrieves a specific property from the item.
  642.    * 
  643.    * @param   Name of the property to retrieve.
  644.    * @return  The value of the property or null if property doesn't exist
  645.    */
  646.   getProperty: function ItemBase_getProperty(aName)
  647.   {
  648.     if (!this.hasProperty(aName))
  649.       return null;
  650.     else
  651.       return this._properties[aName];
  652.   },
  653.   
  654.   /**
  655.    * Sets a specific property for the item.
  656.    * 
  657.    * @param   Name of the property to set.
  658.    * @param   The value to set.
  659.    */
  660.   setProperty: function ItemBase_setProperty(aName, aValue)
  661.   {
  662.     this._properties[aName] = aValue;
  663.   },
  664.   
  665.   /**
  666.    * Removes a property.
  667.    * 
  668.    * @param   Name of property to remove.
  669.    */
  670.   deleteProperty: function ItemBase_deleteProperty(aName)
  671.   {
  672.     //do nothing if property not set
  673.     if (!this.hasProperty(aName))
  674.       return;
  675.     
  676.     //delete the property  
  677.     delete this._properties[aName];  
  678.   },
  679.     
  680.   /**
  681.    * Make a duplicate copy of a item.
  682.    * 
  683.    * @return  A item with the same values as the current item.
  684.    */
  685.   clone: function ItemBase_clone()  
  686.   {
  687.     //create a new item
  688.     var item = Cc[this.contractID].createInstance(this.interfaceID);
  689.                
  690.     //loop through all properties and set on new item
  691.     for (var name in this._properties)
  692.       item.setProperty(name, this._properties[name]);
  693.       
  694.     //return the new item
  695.     return item;             
  696.   },
  697.             
  698.   ////////////////////////////////
  699.   // Internal Functions
  700.   
  701.   /**
  702.    * Helper property to get the main interface.
  703.    */
  704.   get interfaceID() { return gComponents[this._name].interfaceID; }     
  705. };
  706.  
  707. /******************************************************************************
  708.  * Generic service constructor used by different service components as
  709.  * a prototype for the component.
  710.  *
  711.  * @param     Component name.
  712.  ******************************************************************************/
  713. function ServiceBase(aName)
  714. {
  715.   this._name = aName;
  716.   this._ifaces = [this.interfaceID, Ci.ffIService, 
  717.                   Ci.nsIClassInfo, Ci.nsISupports];
  718.   this._bundle = getBundle();  
  719.   this._branch = getBranch(false, null);  
  720. }
  721. ServiceBase.prototype = {
  722.   _name: null,
  723.   _ifaces: null,
  724.   _error: null,
  725.   _bundle: null,
  726.   _branch: null,
  727.      
  728.   ////////////////////////////////
  729.   // nsISupports
  730.   QueryInterface: function ServiceBase_QueryInterface(aIID)
  731.   {
  732.     var ifaces = this.getInterfaces({});
  733.     for (var i=0; i<ifaces.length; i++) {
  734.       if (aIID.equals(ifaces[i]))
  735.         return this;
  736.     }
  737.  
  738.     throw Cr.NS_ERROR_NO_INTERFACE;
  739.   },
  740.             
  741.   ////////////////////////////////
  742.   // nsIClassInfo
  743.   getInterfaces: function ServiceBase_getInterfaces(aCount)
  744.   {
  745.     aCount.value = this._ifaces.length;
  746.     return this._ifaces;
  747.   },
  748.   
  749.   getHelperForLanguage: function ServiceBase_getHelperForLanguage(aLanguage) { return null; },
  750.   get contractID() { return gComponents[this._name].contractID; },
  751.   get classID() { return gComponents[this._name].classID; },
  752.   get classDescription() { return gComponents[this._name].className; },
  753.   get implementationLanguage() { return Ci.nsIProgrammingLanguage.JAVASCRIPT; },
  754.   get flags() { return Ci.nsIClassInfo.SINGLETON; },
  755.             
  756.   ////////////////////////////////
  757.   // ffIService
  758.   
  759.   /**
  760.    * Initialize the component.  Called by the manager service.  Returns false
  761.    * if component could not be loaded.  Chech the lastError property for
  762.    * more information.
  763.    */
  764.   start: function ServiceBase_start() { return true; },
  765.   
  766.   /**
  767.    * Destroy the component.  Called by the manager service.  This may be
  768.    * called prior to start so it needs to be safe.
  769.    */
  770.   stop: function ServiceBase_stop() {},
  771.       
  772.   /**
  773.    * Last error that occurred.
  774.    */
  775.   get lastError() { return this._error; },
  776.   
  777.   /**
  778.    * The default string bundle.
  779.    */
  780.   get bundle() { return this._bundle; },
  781.   
  782.   /**
  783.    * The default user prefernce branch.
  784.    */
  785.   get branch() { return this._branch; },
  786.   
  787.   ////////////////////////////////
  788.   // Internal Functions
  789.   
  790.   /**
  791.    * Helper property to get the main interface.
  792.    */
  793.   get interfaceID() { return gComponents[this._name].interfaceID; }   
  794. };
  795.  
  796. /******************************************************************************
  797.  * Make a component factory used in getClassObject of nsIModule interface.
  798.  *
  799.  * @param   Component constructor.
  800.  * @return  an nsIFactory object.
  801.  *****************************************************************************/  
  802. function makeFactory(aConstructor)
  803. {
  804.   var factory = {
  805.     QueryInterface: function factory_QueryInterface(aIID) 
  806.     {
  807.       if (!aIID.equals(Ci.nsISupports) &&
  808.           !aIID.equals(Ci.nsIFactory))
  809.         throw Cr.NS_ERROR_NO_INTERFACE;
  810.           
  811.       return this;
  812.     },
  813.  
  814.     createInstance: function factory_createInstance(aOuter, aIID) 
  815.     {
  816.       if (aOuter != null)
  817.         throw Cr.NS_ERROR_NO_AGGREGATION;
  818.        
  819.       return (new aConstructor()).QueryInterface(aIID);
  820.     },
  821.     
  822.     lockFactory: function factory_lockFactory(aLock)
  823.     {
  824.       throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  825.     }
  826.   };
  827.  
  828.   //return the factory object
  829.   return factory;    
  830. }
  831.  
  832. /******************************************************************************
  833.  * Load a components script.
  834.  *
  835.  * @param   URL of the script file to load.
  836.  *****************************************************************************/  
  837. function loadScript(aURL)
  838. {  
  839.   //get script loader
  840.   var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
  841.                getService(Ci.mozIJSSubScriptLoader);
  842.                                    
  843.   //load the script
  844.   loader.loadSubScript(aURL, null);
  845. }
  846.  
  847. /******************************************************************************
  848.  * Registration data
  849.  *****************************************************************************/
  850. var gComponents = {
  851.                        
  852.   ErrorItem: {
  853.     classID: Components.ID("{05B9426A-EC5D-4327-99B9-7926AD8491A1}"),
  854.     className: "Forecastfox Error Item",
  855.     contractID: "@ensolis.com/forecastfox/error-item;1",
  856.     interfaceID: Ci.ffIErrorItem,
  857.     scriptLoaded: false,
  858.     scriptURL: "chrome://forecastfox/content/utilities/error-item.js",
  859.     constructor: "ErrorItem"
  860.   },
  861.   
  862.   DiskService: {
  863.     classID: Components.ID("{4386D2C0-560C-45f9-A55F-413FEE243F3D}"),
  864.     className: "Forecastfox Disk I/O Service",
  865.     contractID: "@ensolis.com/forecastfox/disk-service;1",
  866.     interfaceID: Ci.ffIDiskService, 
  867.     scriptLoaded: false,
  868.     scriptURL: "chrome://forecastfox/content/utilities/disk-service.js",
  869.     constructor: "DiskService"
  870.   },
  871.     
  872.   PingService: {
  873.     classID: Components.ID("{0FF66E5D-62B3-4ed2-BF9B-21FCA2CBD357}"),
  874.     className: "Forecastfox Ping Service",
  875.     contractID: "@ensolis.com/forecastfox/ping-service;1", 
  876.     interfaceID: Ci.ffIPingService, 
  877.     scriptLoaded: false,
  878.     scriptURL: "chrome://forecastfox/content/ping/ping-service.js",
  879.     constructor: "PingService"
  880.   },
  881.                                
  882.   ResolverItem: {
  883.     classID: Components.ID("{0B770FA3-40C6-4a37-806E-6A47E0FFADAE}"),
  884.     className: "Forecastfox Namespace Resolver Item",
  885.     contractID: "@ensolis.com/forecastfox/resolver-item;1", 
  886.     interfaceID: Ci.nsIDOMXPathNSResolver,
  887.     scriptLoaded: false,
  888.     scriptURL: "chrome://forecastfox/content/parser/resolver-item.js",
  889.     constructor: "ResolverItem"
  890.   },
  891.                       
  892.   ConverterItem: {
  893.     classID: Components.ID("{A8102480-27EA-432a-AC68-5161B3E45CC0}"),
  894.     className: "Forecastfox Converter Item",
  895.     contractID: "@ensolis.com/forecastfox/converter-item;1", 
  896.     interfaceID: Ci.ffIConverterItem,
  897.     scriptLoaded: false,
  898.     scriptURL: "chrome://forecastfox/content/parser/converter-item.js",
  899.     constructor: "ConverterItem"
  900.   },
  901.                    
  902.   ConverterService: {
  903.     classID: Components.ID("{0DEC2682-40DB-4b51-A1E5-085991D800D9}"),
  904.     className: "Forecastfox Converter Service",
  905.     contractID: "@ensolis.com/forecastfox/converter-service;1", 
  906.     interfaceID: Ci.ffIConverterService, 
  907.     scriptLoaded: false,
  908.     scriptURL: "chrome://forecastfox/content/parser/converter-service.js",
  909.     constructor: "ConverterService"
  910.   },
  911.                        
  912.   ParserItem: {
  913.     classID: Components.ID("{FC48D906-4F00-4ee0-A035-DEE0CE5AFB9D}"),
  914.     className: "Forecastfox Parser Item",
  915.     contractID: "@ensolis.com/forecastfox/parser-item;1", 
  916.     interfaceID: Ci.ffIParserItem,
  917.     scriptLoaded: false,
  918.     scriptURL: "chrome://forecastfox/content/parser/parser-item.js",
  919.     constructor: "ParserItem"
  920.   },
  921.                    
  922.   ParserService: {
  923.     classID: Components.ID("{1CE4E984-6F2A-4ac8-BE74-8E47C0F4B445}"),
  924.     className: "Forecastfox Parser Service",
  925.     contractID: "@ensolis.com/forecastfox/parser-service;1", 
  926.     interfaceID: Ci.ffIParserService, 
  927.     scriptLoaded: false,
  928.     scriptURL: "chrome://forecastfox/content/parser/parser-service.js",
  929.     constructor: "ParserService"
  930.   },
  931.   
  932.   ProfileItem: {
  933.     classID: Components.ID("{F41536F9-D435-42fe-A362-32217C972418}"),
  934.     className: "Forecastfox Profile Item",
  935.     contractID: "@ensolis.com/forecastfox/profile-item;1", 
  936.     interfaceID: Ci.ffIProfileItem,
  937.     scriptLoaded: false,
  938.     scriptURL: "chrome://forecastfox/content/profiles/profile-item.js",
  939.     constructor: "ProfileItem"
  940.   },   
  941.                    
  942.   ProfileService: {
  943.     classID: Components.ID("{01F8B6C4-F9E1-4dc8-A980-5A9985CD4111}"),
  944.     className: "Forecastfox Profile Service",
  945.     contractID: "@ensolis.com/forecastfox/profile-service;1", 
  946.     interfaceID: Ci.ffIProfileService, 
  947.     scriptLoaded: false,
  948.     scriptURL: "chrome://forecastfox/content/profiles/profile-service.js",
  949.     constructor: "ProfileService"
  950.   },
  951.                    
  952.   MigratorService: {
  953.     classID: Components.ID("{E938FEBC-166F-498c-A35E-654BB0E2DE7E}"),
  954.     className: "Forecastfox Migrator Service",
  955.     contractID: "@ensolis.com/forecastfox/migrator-service;1", 
  956.     interfaceID: Ci.ffIMigratorService, 
  957.     scriptLoaded: false,
  958.     scriptURL: "chrome://forecastfox/content/profiles/migrator-service.js",
  959.     constructor: "MigratorService"
  960.   },
  961.    
  962.   IconItem: {
  963.     classID: Components.ID("{B1DB225E-C16C-452f-B042-F917732D9C2E}"),
  964.     className: "Forecastfox Icon Item",
  965.     contractID: "@ensolis.com/forecastfox/icon-item;1", 
  966.     interfaceID: Ci.ffIIconItem,
  967.     scriptLoaded: false,
  968.     scriptURL: "chrome://forecastfox/content/icons/icon-item.js",
  969.     constructor: "IconItem"
  970.   },
  971.                        
  972.   PackItem: {
  973.     classID: Components.ID("{0666DE3E-4F11-4e0f-9154-894DAA76CC6E}"),
  974.     className: "Forecastfox Pack Item",
  975.     contractID: "@ensolis.com/forecastfox/pack-item;1",
  976.     interfaceID: Ci.ffIPackItem,
  977.     scriptLoaded: false,
  978.     scriptURL: "chrome://forecastfox/content/icons/pack-item.js",
  979.     constructor: "PackItem"
  980.   },                              
  981.   
  982.   PackService: {
  983.     classID: Components.ID("{0AC191C4-F5C5-4590-B95D-46602B430598}"),
  984.     className: "Forecastfox Icon Pack Service",
  985.     contractID: "@ensolis.com/forecastfox/pack-service;1", 
  986.     interfaceID: Ci.ffIPackService, 
  987.     scriptLoaded: false,
  988.     scriptURL: "chrome://forecastfox/content/icons/pack-service.js",
  989.     constructor: "PackService"
  990.   },
  991.     
  992.   WebService: {
  993.     classID: Components.ID("{9172437D-0D7D-4f86-B3E9-0D57AAFA541C}"),
  994.     className: "Forecastfox Web Service",
  995.     contractID: "@ensolis.com/forecastfox/web-service;1", 
  996.     interfaceID: Ci.ffIWebService, 
  997.     scriptLoaded: false,
  998.     scriptURL: "chrome://forecastfox/content/icons/web-service.js",
  999.     constructor: "WebService",
  1000.     category: "JavaScript global property",
  1001.     entry: "forecastfox"
  1002.   },
  1003.                                                              
  1004.   ManagerService: {
  1005.     classID: Components.ID("{5ADF9E4D-EAA6-4223-853D-D932060094E0}"),
  1006.     className: "Forecastfox Manager Service",
  1007.     contractID: "@ensolis.com/forecastfox/manager-service;1", 
  1008.     interfaceID: Ci.ffIManagerService, 
  1009.     scriptLoaded: false,
  1010.     scriptURL: "chrome://forecastfox/content/utilities/manager-service.js",
  1011.     constructor: "ManagerService"
  1012.   }    
  1013. };
  1014.  
  1015. /******************************************************************************
  1016.  * Object that implements the nsIModule interface
  1017.  *****************************************************************************/
  1018. var gModule = {
  1019.  
  1020.   registerSelf: function gModule_registerSelf(aCompMgr, aFileSpec, aLocation, aType) 
  1021.   {      
  1022.     //get the component registrar
  1023.     var compMgr = aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
  1024.     
  1025.     //get the category manager
  1026.     var catMgr = Cc["@mozilla.org/categorymanager;1"].
  1027.                  getService(Ci.nsICategoryManager);
  1028.                  
  1029.     //loop through components registration data             
  1030.     for (var name in gComponents) {
  1031.       var comp = gComponents[name];
  1032.  
  1033.       //register factory location
  1034.       compMgr.registerFactoryLocation(comp.classID, comp.className, 
  1035.                                       comp.contractID, aFileSpec,
  1036.                                       aLocation, aType); 
  1037.       
  1038.       //register category                                
  1039.       if (comp.hasOwnProperty("category"))
  1040.         catMgr.addCategoryEntry(comp.category, comp.entry, 
  1041.                                 comp.contractID, true, true);                                      
  1042.                                                            
  1043.     }
  1044.   },
  1045.  
  1046.   unregisterSelf: function gModule_unregisterSelf(aCompMgr, aLocation, aType)
  1047.   {
  1048.     //get the component registrar  
  1049.     var compMgr = aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
  1050.     
  1051.     //get the category manager
  1052.     var catMgr = Cc["@mozilla.org/categorymanager;1"].
  1053.                  getService(Ci.nsICategoryManager);
  1054.                                       
  1055.     //loop through components registration data             
  1056.     for (var name in gComponents) {
  1057.       var comp = gComponents[name];
  1058.       
  1059.       //unregister factory location
  1060.       compMgr.unregisterFactoryLocation(comp.classID, aLocation);  
  1061.       
  1062.       //unregister category                                
  1063.       if (comp.hasOwnProperty("category"))      
  1064.         catMgr.deleteCategoryEntry(comp.category, comp.entry,
  1065.                                    comp.contractID, true);                                         
  1066.     }        
  1067.   },
  1068.   
  1069.   getClassObject: function gModule_getClassObject(aCompMgr, aCID, aIID) 
  1070.   {
  1071.     //throw if not requesting a factory
  1072.     if (!aIID.equals(Ci.nsIFactory))
  1073.       throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  1074.       
  1075.     //loop through components registration data             
  1076.     for (var name in gComponents) {
  1077.       var comp = gComponents[name];
  1078.  
  1079.       //component matches  
  1080.       if (aCID.equals(comp.classID)) {
  1081.         
  1082.         //load the script if it isn't loaded
  1083.         if (!comp.scriptLoaded) {
  1084.           loadScript(comp.scriptURL);
  1085.           comp.scriptLoaded = true;
  1086.         }
  1087.             
  1088.         //return factory
  1089.         return makeFactory(eval(comp.constructor));
  1090.       }
  1091.     }
  1092.     
  1093.     //throw if not found
  1094.     throw Cr.NS_ERROR_NO_INTERFACE;
  1095.   },
  1096.  
  1097.   canUnload: function gModule_canUnload(compMgr) { return true; }
  1098. };
  1099.  
  1100. /******************************************************************************
  1101.  * Module entry point
  1102.  *****************************************************************************/
  1103. function NSGetModule(compMgr, fileSpec) 
  1104. {
  1105.   return gModule;
  1106. }