home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / phoenx05.zip / phoenix / components / nsSidebar.js < prev    next >
Text File  |  2002-12-10  |  18KB  |  469 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is mozilla.org code.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are
  16.  * Copyright (C) 1999 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s): Stephen Lamm            <slamm@netscape.com>
  20.  *                 Robert John Churchill   <rjc@netscape.com>
  21.  */
  22.  
  23. /*
  24.  * No magic constructor behaviour, as is de rigeur for XPCOM.
  25.  * If you must perform some initialization, and it could possibly fail (even
  26.  * due to an out-of-memory condition), you should use an Init method, which
  27.  * can convey failure appropriately (thrown exception in JS,
  28.  * NS_FAILED(nsresult) return in C++).
  29.  *
  30.  * In JS, you can actually cheat, because a thrown exception will cause the
  31.  * CreateInstance call to fail in turn, but not all languages are so lucky.
  32.  * (Though ANSI C++ provides exceptions, they are verboten in Mozilla code
  33.  * for portability reasons -- and even when you're building completely
  34.  * platform-specific code, you can't throw across an XPCOM method boundary.)
  35.  */
  36.  
  37. const DEBUG = false; /* set to false to suppress debug messages */
  38. const PANELS_RDF_FILE  = "UPnls"; /* directory services property to find panels.rdf */
  39.  
  40. const SIDEBAR_CONTRACTID   = "@mozilla.org/sidebar;1";
  41. const SIDEBAR_CID      = Components.ID("{22117140-9c6e-11d3-aaf1-00805f8a4905}");
  42. const CONTAINER_CONTRACTID = "@mozilla.org/rdf/container;1";
  43. const DIR_SERV_CONTRACTID  = "@mozilla.org/file/directory_service;1"
  44. const NETSEARCH_CONTRACTID = "@mozilla.org/rdf/datasource;1?name=internetsearch"
  45. const IO_SERV_CONTRACTID   = "@mozilla.org/network/io-service;1";
  46. const nsISupports      = Components.interfaces.nsISupports;
  47. const nsIFactory       = Components.interfaces.nsIFactory;
  48. const nsISidebar       = Components.interfaces.nsISidebar;
  49. const nsIRDFContainer  = Components.interfaces.nsIRDFContainer;
  50. const nsIProperties    = Components.interfaces.nsIProperties;
  51. const nsIFileURL       = Components.interfaces.nsIFileURL;
  52. const nsIRDFRemoteDataSource = Components.interfaces.nsIRDFRemoteDataSource;
  53. const nsIInternetSearchService = Components.interfaces.nsIInternetSearchService;
  54. const nsIClassInfo = Components.interfaces.nsIClassInfo;
  55.  
  56. function nsSidebar()
  57. {
  58.     const RDF_CONTRACTID = "@mozilla.org/rdf/rdf-service;1";
  59.     const nsIRDFService = Components.interfaces.nsIRDFService;
  60.     
  61.     this.rdf = Components.classes[RDF_CONTRACTID].getService(nsIRDFService);
  62.     this.datasource_uri = getSidebarDatasourceURI(PANELS_RDF_FILE);
  63.     debug('datasource_uri is ' + this.datasource_uri);
  64.     this.resource = 'urn:sidebar:current-panel-list';
  65.     this.datasource = this.rdf.GetDataSource(this.datasource_uri);
  66. }
  67.  
  68. nsSidebar.prototype.nc = "http://home.netscape.com/NC-rdf#";
  69.  
  70. nsSidebar.prototype.setWindow =
  71. function (aWindow)
  72. {    
  73.     this.window = aWindow;    
  74. }
  75.  
  76. nsSidebar.prototype.isPanel =
  77. function (aContentURL)
  78. {
  79.     var container = 
  80.         Components.classes[CONTAINER_CONTRACTID].createInstance(nsIRDFContainer);
  81.  
  82.     container.Init(this.datasource, this.rdf.GetResource(this.resource));
  83.     
  84.     /* Create a resource for the new panel and add it to the list */
  85.     var panel_resource = 
  86.         this.rdf.GetResource("urn:sidebar:3rdparty-panel:" + aContentURL);
  87.  
  88.     return (container.IndexOf(panel_resource) != -1);
  89. }
  90.  
  91. function sidebarURLSecurityCheck(url)
  92. {
  93.     if (url.search(/(^http:|^ftp:|^https:)/) == -1)
  94.         throw "Script attempted to add sidebar panel from illegal source";
  95. }
  96.  
  97. /* decorate prototype to provide ``class'' methods and property accessors */
  98. nsSidebar.prototype.addPanel =
  99. function (aTitle, aContentURL, aCustomizeURL)
  100. {
  101.     debug("addPanel(" + aTitle + ", " + aContentURL + ", " +
  102.           aCustomizeURL + ")");
  103.    
  104.     return this.addPanelInternal(aTitle, aContentURL, aCustomizeURL, false);
  105. }
  106.  
  107. nsSidebar.prototype.addPersistentPanel = 
  108. function(aTitle, aContentURL, aCustomizeURL)
  109. {
  110.     debug("addPersistentPanel(" + aTitle + ", " + aContentURL + ", " +
  111.            aCustomizeURL + ")\n");
  112.  
  113.     return this.addPanelInternal(aTitle, aContentURL, aCustomizeURL, true);
  114. }
  115.  
  116. nsSidebar.prototype.addPanelInternal =
  117. function (aTitle, aContentURL, aCustomizeURL, aPersist)
  118. {
  119.     if (!this.window)
  120.     {
  121.         debug ("no window object set, bailing out.");
  122.         throw Components.results.NS_ERROR_NOT_INITIALIZED;
  123.     }
  124.  
  125.     sidebarURLSecurityCheck(aContentURL);
  126.  
  127.     // Create a "container" wrapper around the current panels to
  128.     // manipulate the RDF:Seq more easily.
  129.     var panel_list = this.datasource.GetTarget(this.rdf.GetResource(this.resource), this.rdf.GetResource(nsSidebar.prototype.nc+"panel-list"), true);
  130.     if (panel_list) {
  131.         panel_list.QueryInterface(Components.interfaces.nsIRDFResource);
  132.     } else {
  133.         // Datasource is busted. Start over.
  134.         debug("Sidebar datasource is busted\n");
  135.     }
  136.  
  137.     var container = Components.classes[CONTAINER_CONTRACTID].createInstance(nsIRDFContainer);
  138.     container.Init(this.datasource, panel_list);
  139.  
  140.     /* Create a resource for the new panel and add it to the list */
  141.     var panel_resource = 
  142.         this.rdf.GetResource("urn:sidebar:3rdparty-panel:" + aContentURL);
  143.     var panel_index = container.IndexOf(panel_resource);
  144.     var stringBundle, brandStringBundle, titleMessage, dialogMessage, promptService;
  145.     if (panel_index != -1)
  146.     {
  147.         try {
  148.             stringBundle = srGetStrBundle("chrome://communicator/locale/sidebar/sidebar.properties");
  149.             brandStringBundle = srGetStrBundle("chrome://global/locale/brand.properties");
  150.             if (stringBundle) {
  151.                 sidebarName = brandStringBundle.GetStringFromName("sidebarName");
  152.                 titleMessage = stringBundle.GetStringFromName("dupePanelAlertTitle");
  153.                 dialogMessage = stringBundle.GetStringFromName("dupePanelAlertMessage");
  154.                 dialogMessage = dialogMessage.replace(/%url%/, aContentURL);
  155.                 dialogMessage = dialogMessage.replace(/%name%/, sidebarName);
  156.             }
  157.         }
  158.         catch (e) {
  159.             titleMessage = "Sidebar";
  160.             dialogMessage = aContentURL + " already exists in Sidebar.  No string bundle";
  161.         }
  162.           
  163.         promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
  164.         if (promptService) {
  165.           promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
  166.           promptService.alert(this.window, titleMessage, dialogMessage);
  167.         }
  168.  
  169.         return;
  170.     }
  171.  
  172.     try {
  173.         stringBundle = srGetStrBundle("chrome://communicator/locale/sidebar/sidebar.properties");
  174.         brandStringBundle = srGetStrBundle("chrome://global/locale/brand.properties");
  175.         if (stringBundle) {
  176.             sidebarName = brandStringBundle.GetStringFromName("sidebarName");
  177.             titleMessage = stringBundle.GetStringFromName("addPanelConfirmTitle");
  178.             dialogMessage = stringBundle.GetStringFromName("addPanelConfirmMessage");
  179.             if (aPersist)
  180.             {
  181.                 var warning = stringBundle.GetStringFromName("persistentPanelWarning");
  182.                 dialogMessage += "\n" + warning;
  183.             }
  184.             dialogMessage = dialogMessage.replace(/%title%/, aTitle);
  185.             dialogMessage = dialogMessage.replace(/%url%/, aContentURL);
  186.             dialogMessage = dialogMessage.replace(/#/g, "\n");
  187.             dialogMessage = dialogMessage.replace(/%name%/g, sidebarName);
  188.         }
  189.     }
  190.     catch (e) {
  191.         titleMessage = "Add Tab to Sidebar";
  192.         dialogMessage = "No string bundle.  Add the Tab '" + aTitle + "' to Sidebar?\n\n" + "Source: " + aContentURL;
  193.     }
  194.           
  195.     promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
  196.     promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
  197.     var rv = promptService.confirm(this.window, titleMessage, dialogMessage);
  198.       
  199.     if (!rv)
  200.         return;
  201.  
  202.     /* Now make some sidebar-ish assertions about it... */
  203.     this.datasource.Assert(panel_resource,
  204.                            this.rdf.GetResource(this.nc + "title"),
  205.                            this.rdf.GetLiteral(aTitle),
  206.                            true);
  207.     this.datasource.Assert(panel_resource,
  208.                            this.rdf.GetResource(this.nc + "content"),
  209.                            this.rdf.GetLiteral(aContentURL),
  210.                            true);
  211.     if (aCustomizeURL)
  212.         this.datasource.Assert(panel_resource,
  213.                                this.rdf.GetResource(this.nc + "customize"),
  214.                                this.rdf.GetLiteral(aCustomizeURL),
  215.                                true);
  216.     var persistValue = aPersist ? "true" : "false";
  217.     this.datasource.Assert(panel_resource,
  218.                            this.rdf.GetResource(this.nc + "persist"),
  219.                            this.rdf.GetLiteral(persistValue),
  220.                            true);
  221.         
  222.     container.AppendElement(panel_resource);
  223.  
  224.     // Use an assertion to pass a "refresh" event to all the sidebars.
  225.     // They use observers to watch for this assertion (in sidebarOverlay.js).
  226.     this.datasource.Assert(this.rdf.GetResource(this.resource),
  227.                            this.rdf.GetResource(this.nc + "refresh"),
  228.                            this.rdf.GetLiteral("true"),
  229.                            true);
  230.     this.datasource.Unassert(this.rdf.GetResource(this.resource),
  231.                              this.rdf.GetResource(this.nc + "refresh"),
  232.                              this.rdf.GetLiteral("true"));
  233.  
  234.     /* Write the modified panels out. */
  235.     this.datasource.QueryInterface(nsIRDFRemoteDataSource).Flush();
  236.  
  237. }
  238.  
  239. /* decorate prototype to provide ``class'' methods and property accessors */
  240. nsSidebar.prototype.addSearchEngine =
  241. function (engineURL, iconURL, suggestedTitle, suggestedCategory)
  242. {
  243.     debug("addSearchEngine(" + engineURL + ", " + iconURL + ", " +
  244.           suggestedCategory + ", " + suggestedTitle + ")");
  245.  
  246.     if (!this.window)
  247.     {
  248.         debug ("no window object set, bailing out.");
  249.         throw Components.results.NS_ERROR_NOT_INITIALIZED;
  250.     }
  251.  
  252.     try
  253.     {
  254.         // make sure using HTTP (for both engine as well as icon URLs)
  255.  
  256.         if (engineURL.search(/^http:\/\//i) == -1)
  257.         {
  258.             debug ("must use HTTP to fetch search engine file");
  259.             throw Components.results.NS_ERROR_INVALID_ARG;
  260.         }
  261.  
  262.         if (iconURL.search(/^http:\/\//i) == -1)
  263.         {
  264.             debug ("must use HTTP to fetch search icon file");
  265.             throw Components.results.NS_ERROR_INVALID_ARG;
  266.         }
  267.  
  268.         // make sure engineURL refers to a .src file
  269.         if (engineURL.search(/\.src$/i) == -1)
  270.         {
  271.             debug ("engineURL doesn't reference a .src file");
  272.             throw Components.results.NS_ERROR_INVALID_ARG;
  273.         }
  274.  
  275.         // make sure iconURL refers to a .gif/.jpg/.jpeg/.png file
  276.         if (iconURL.search(/\.(gif|jpg|jpeg|png)$/i) == -1)
  277.         {
  278.             debug ("iconURL doesn't reference a supported image file");
  279.             throw Components.results.NS_ERROR_INVALID_ARG;
  280.         }
  281.  
  282.     }
  283.     catch(ex)
  284.     {
  285.         this.window.alert("Failed to add the search engine.\n");
  286.         throw Components.results.NS_ERROR_INVALID_ARG;
  287.     }
  288.  
  289.     var titleMessage, dialogMessage;
  290.     try {
  291.         var stringBundle = srGetStrBundle("chrome://communicator/locale/sidebar/sidebar.properties");
  292.         var brandStringBundle = srGetStrBundle("chrome://global/locale/brand.properties");
  293.         if (stringBundle) {
  294.             sidebarName = brandStringBundle.GetStringFromName("sidebarName");            
  295.             titleMessage = stringBundle.GetStringFromName("addEngineConfirmTitle");
  296.             dialogMessage = stringBundle.GetStringFromName("addEngineConfirmMessage");
  297.             dialogMessage = dialogMessage.replace(/%title%/, suggestedTitle);
  298.             dialogMessage = dialogMessage.replace(/%category%/, suggestedCategory);
  299.             dialogMessage = dialogMessage.replace(/%url%/, engineURL);
  300.             dialogMessage = dialogMessage.replace(/#/g, "\n");
  301.             dialogMessage = dialogMessage.replace(/%name%/, sidebarName);
  302.         }
  303.     }
  304.     catch (e) {
  305.         titleMessage = "Add Search Engine";
  306.         dialogMessage = "Add the following search engine?\n\nName: " + suggestedTitle;
  307.         dialogMessage += "\nSearch Category: " + suggestedCategory;
  308.         dialogMessage += "\nSource: " + engineURL;
  309.     }
  310.           
  311.     var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
  312.     promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
  313.     var rv = promptService.confirm(this.window, titleMessage, dialogMessage);
  314.       
  315.     if (!rv)
  316.         return;
  317.  
  318.     var internetSearch = Components.classes[NETSEARCH_CONTRACTID].getService();
  319.     if (internetSearch)    
  320.         internetSearch = internetSearch.QueryInterface(nsIInternetSearchService);
  321.     if (internetSearch)
  322.     {
  323.         internetSearch.AddSearchEngine(engineURL, iconURL, suggestedTitle,
  324.                                        suggestedCategory);
  325.     }
  326. }
  327.  
  328. // property of nsIClassInfo
  329. nsSidebar.prototype.flags = nsIClassInfo.DOM_OBJECT;
  330.  
  331. // property of nsIClassInfo
  332. nsSidebar.prototype.classDescription = "Sidebar";
  333.  
  334. // method of nsIClassInfo
  335. nsSidebar.prototype.getInterfaces = function(count) {
  336.     var interfaceList = [nsISidebar, nsIClassInfo];
  337.     count.value = interfaceList.length;
  338.     return interfaceList;
  339. }
  340.  
  341. // method of nsIClassInfo
  342. nsSidebar.prototype.getHelperForLanguage = function(count) {return null;}
  343.  
  344. nsSidebar.prototype.QueryInterface =
  345. function (iid) {
  346.     if (!iid.equals(nsISidebar) && 
  347.         !iid.equals(nsIClassInfo) &&
  348.         !iid.equals(nsISupports))
  349.         throw Components.results.NS_ERROR_NO_INTERFACE;
  350.     return this;
  351. }
  352.  
  353. var sidebarModule = new Object();
  354.  
  355. sidebarModule.registerSelf =
  356. function (compMgr, fileSpec, location, type)
  357. {
  358.     debug("registering (all right -- a JavaScript module!)");
  359.     compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  360.  
  361.     compMgr.registerFactoryLocation(SIDEBAR_CID, 
  362.                                     "Sidebar JS Component",
  363.                                     SIDEBAR_CONTRACTID, 
  364.                                     fileSpec, 
  365.                                     location,
  366.                                     type);
  367. }
  368.  
  369. sidebarModule.getClassObject =
  370. function (compMgr, cid, iid) {
  371.     if (!cid.equals(SIDEBAR_CID))
  372.         throw Components.results.NS_ERROR_NO_INTERFACE;
  373.     
  374.     if (!iid.equals(Components.interfaces.nsIFactory))
  375.         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  376.     
  377.     return sidebarFactory;
  378. }
  379.  
  380. sidebarModule.canUnload =
  381. function(compMgr)
  382. {
  383.     debug("Unloading component.");
  384.     return true;
  385. }
  386.     
  387. /* factory object */
  388. var sidebarFactory = new Object();
  389.  
  390. sidebarFactory.createInstance =
  391. function (outer, iid) {
  392.     debug("CI: " + iid);
  393.     if (outer != null)
  394.         throw Components.results.NS_ERROR_NO_AGGREGATION;
  395.  
  396.     return (new nsSidebar()).QueryInterface(iid);
  397. }
  398.  
  399. /* entrypoint */
  400. function NSGetModule(compMgr, fileSpec) {
  401.     return sidebarModule;
  402. }
  403.  
  404. /* static functions */
  405. if (DEBUG)
  406.     debug = function (s) { dump("-*- sidebar component: " + s + "\n"); }
  407. else
  408.     debug = function (s) {}
  409.  
  410. function getSidebarDatasourceURI(panels_file_id)
  411. {
  412.     try 
  413.     {
  414.         /* use the fileLocator to look in the profile directory 
  415.          * to find 'panels.rdf', which is the
  416.          * database of the user's currently selected panels. */
  417.         var directory_service = Components.classes[DIR_SERV_CONTRACTID].getService(Components.interfaces.nsIProperties);
  418.  
  419.         /* if <profile>/panels.rdf doesn't exist, get will copy
  420.          *bin/defaults/profile/panels.rdf to <profile>/panels.rdf */
  421.         var sidebar_file = directory_service.get(panels_file_id, Components.interfaces.nsIFile);
  422.  
  423.         if (!sidebar_file.exists())
  424.         {
  425.             /* this should not happen, as GetFileLocation() should copy
  426.              * defaults/panels.rdf to the users profile directory */
  427.             debug("sidebar file does not exist");
  428.             return null;
  429.         }
  430.  
  431.         var io_service = Components.classes[IO_SERV_CONTRACTID].getService(Components.interfaces.nsIIOService);
  432.         var file_handler = io_service.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  433.         var sidebar_uri = file_handler.getURLSpecFromFile(sidebar_file);
  434.         debug("sidebar uri is " + sidebar_uri);
  435.         return sidebar_uri;
  436.     }
  437.     catch (ex)
  438.     {
  439.         /* this should not happen */
  440.         debug("caught " + ex + " getting sidebar datasource uri");
  441.         return null;
  442.     }
  443. }
  444.  
  445.  
  446. var strBundleService = null;
  447. function srGetStrBundle(path)
  448. {
  449.    var strBundle = null;
  450.    if (!strBundleService) {
  451.        try {
  452.           strBundleService =
  453.           Components.classes["@mozilla.org/intl/stringbundle;1"].getService(); 
  454.           strBundleService = 
  455.           strBundleService.QueryInterface(Components.interfaces.nsIStringBundleService);
  456.        } catch (ex) {
  457.           dump("\n--** strBundleService failed: " + ex + "\n");
  458.           return null;
  459.       }
  460.    }
  461.    strBundle = strBundleService.createBundle(path); 
  462.    if (!strBundle) {
  463.        dump("\n--** strBundle createInstance failed **--\n");
  464.    }
  465.    return strBundle;
  466. }
  467.  
  468.  
  469.