home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 January / 01_02.iso / software / netscape62win / browser.xpi / bin / components / nsSidebar.js < prev    next >
Text File  |  2001-08-10  |  17KB  |  428 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 nsISupports      = Components.interfaces.nsISupports;
  46. const nsIFactory       = Components.interfaces.nsIFactory;
  47. const nsISidebar       = Components.interfaces.nsISidebar;
  48. const nsIRDFContainer  = Components.interfaces.nsIRDFContainer;
  49. const nsIProperties    = Components.interfaces.nsIProperties;
  50. const nsIFileURL       = Components.interfaces.nsIFileURL;
  51. const nsIRDFRemoteDataSource = Components.interfaces.nsIRDFRemoteDataSource;
  52. const nsIInternetSearchService = Components.interfaces.nsIInternetSearchService;
  53. const nsIClassInfo = Components.interfaces.nsIClassInfo;
  54.  
  55. function nsSidebar()
  56. {
  57.     const RDF_CONTRACTID = "@mozilla.org/rdf/rdf-service;1";
  58.     const nsIRDFService = Components.interfaces.nsIRDFService;
  59.     
  60.     this.rdf = Components.classes[RDF_CONTRACTID].getService(nsIRDFService);
  61.     this.datasource_uri = getSidebarDatasourceURI(PANELS_RDF_FILE);
  62.     debug('datasource_uri is ' + this.datasource_uri);
  63.     this.resource = 'urn:sidebar:current-panel-list';
  64.     this.datasource = this.rdf.GetDataSource(this.datasource_uri);
  65. }
  66.  
  67. nsSidebar.prototype.nc = "http://home.netscape.com/NC-rdf#";
  68.  
  69. nsSidebar.prototype.setWindow =
  70. function (aWindow)
  71. {    
  72.     this.window = aWindow;    
  73. }
  74.  
  75. nsSidebar.prototype.isPanel =
  76. function (aContentURL)
  77. {
  78.     var container = 
  79.         Components.classes[CONTAINER_CONTRACTID].createInstance(nsIRDFContainer);
  80.  
  81.     container.Init(this.datasource, this.rdf.GetResource(this.resource));
  82.     
  83.     /* Create a resource for the new panel and add it to the list */
  84.     var panel_resource = 
  85.         this.rdf.GetResource("urn:sidebar:3rdparty-panel:" + aContentURL);
  86.  
  87.     return (container.IndexOf(panel_resource) != -1);
  88. }
  89.  
  90. function sidebarURLSecurityCheck(url)
  91. {
  92.     if (url.search(/(^http:|^ftp:|^https:)/) == -1)
  93.         throw "Script attempted to add sidebar panel from illegal source";
  94. }
  95.  
  96. /* decorate prototype to provide ``class'' methods and property accessors */
  97. nsSidebar.prototype.addPanel =
  98. function (aTitle, aContentURL, aCustomizeURL)
  99. {
  100.     debug("addPanel(" + aTitle + ", " + aContentURL + ", " +
  101.           aCustomizeURL + ")");
  102.  
  103.     if (!this.window)
  104.     {
  105.         debug ("no window object set, bailing out.");
  106.         throw Components.results.NS_ERROR_NOT_INITIALIZED;
  107.     }
  108.  
  109.     sidebarURLSecurityCheck(aContentURL);
  110.  
  111.     // Create a "container" wrapper around the current panels to
  112.     // manipulate the RDF:Seq more easily.
  113.     var panel_list = this.datasource.GetTarget(this.rdf.GetResource(this.resource), this.rdf.GetResource(nsSidebar.prototype.nc+"panel-list"), true);
  114.     if (panel_list) {
  115.         panel_list.QueryInterface(Components.interfaces.nsIRDFResource);
  116.     } else {
  117.         // Datasource is busted. Start over.
  118.         debug("Sidebar datasource is busted\n");
  119.   }
  120.  
  121.     var container = Components.classes[CONTAINER_CONTRACTID].createInstance(nsIRDFContainer);
  122.     container.Init(this.datasource, panel_list);
  123.  
  124.     /* Create a resource for the new panel and add it to the list */
  125.     var panel_resource = 
  126.         this.rdf.GetResource("urn:sidebar:3rdparty-panel:" + aContentURL);
  127.     var panel_index = container.IndexOf(panel_resource);
  128.     if (panel_index != -1)
  129.     {
  130.         var titleMessage, dialogMessage;
  131.         try {
  132.             var stringBundle = srGetStrBundle("chrome://communicator/locale/sidebar/sidebar.properties");
  133.             var brandStringBundle = srGetStrBundle("chrome://global/locale/brand.properties");
  134.             if (stringBundle) {
  135.                 sidebarName = brandStringBundle.GetStringFromName("sidebarName");
  136.                 titleMessage = stringBundle.GetStringFromName("dupePanelAlertTitle");
  137.                 dialogMessage = stringBundle.GetStringFromName("dupePanelAlertMessage");
  138.                 dialogMessage = dialogMessage.replace(/%url%/, aContentURL);
  139.                 dialogMessage = dialogMessage.replace(/%name%/, sidebarName);
  140.             }
  141.         }
  142.         catch (e) {
  143.             titleMessage = "Sidebar";
  144.             dialogMessage = aContentURL + " already exists in Sidebar.  No string bundle";
  145.         }
  146.           
  147.         var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
  148.         if (promptService) {
  149.           promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
  150.           promptService.alert(this.window, titleMessage, dialogMessage);
  151.         }
  152.  
  153.         return;
  154.     }
  155.     
  156.     var titleMessage, dialogMessage;
  157.     try {
  158.         var stringBundle = srGetStrBundle("chrome://communicator/locale/sidebar/sidebar.properties");
  159.         var brandStringBundle = srGetStrBundle("chrome://global/locale/brand.properties");
  160.         if (stringBundle) {
  161.             sidebarName = brandStringBundle.GetStringFromName("sidebarName");
  162.             titleMessage = stringBundle.GetStringFromName("addPanelConfirmTitle");
  163.             dialogMessage = stringBundle.GetStringFromName("addPanelConfirmMessage");
  164.             dialogMessage = dialogMessage.replace(/%title%/, aTitle);
  165.             dialogMessage = dialogMessage.replace(/%url%/, aContentURL);
  166.             dialogMessage = dialogMessage.replace(/#/g, "\n");
  167.             dialogMessage = dialogMessage.replace(/%name%/, sidebarName);
  168.         }
  169.     }
  170.     catch (e) {
  171.         titleMessage = "Add Tab to Sidebar";
  172.         dialogMessage = "No string bundle.  Add the Tab '" + aTitle + "' to Sidebar?\n\n" + "Source: " + aContentURL;
  173.     }
  174.           
  175.     var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
  176.     promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
  177.     var rv = promptService.confirm(this.window, titleMessage, dialogMessage);
  178.       
  179.     if (!rv)
  180.         return;
  181.  
  182.     /* Now make some sidebar-ish assertions about it... */
  183.     this.datasource.Assert(panel_resource,
  184.                            this.rdf.GetResource(this.nc + "title"),
  185.                            this.rdf.GetLiteral(aTitle),
  186.                            true);
  187.     this.datasource.Assert(panel_resource,
  188.                            this.rdf.GetResource(this.nc + "content"),
  189.                            this.rdf.GetLiteral(aContentURL),
  190.                            true);
  191.     if (aCustomizeURL)
  192.         this.datasource.Assert(panel_resource,
  193.                                this.rdf.GetResource(this.nc + "customize"),
  194.                                this.rdf.GetLiteral(aCustomizeURL),
  195.                                true);
  196.         
  197.     container.AppendElement(panel_resource);
  198.  
  199.     // Use an assertion to pass a "refresh" event to all the sidebars.
  200.     // They use observers to watch for this assertion (in sidebarOverlay.js).
  201.     this.datasource.Assert(this.rdf.GetResource(this.resource),
  202.                            this.rdf.GetResource(this.nc + "refresh"),
  203.                            this.rdf.GetLiteral("true"),
  204.                            true);
  205.     this.datasource.Unassert(this.rdf.GetResource(this.resource),
  206.                              this.rdf.GetResource(this.nc + "refresh"),
  207.                              this.rdf.GetLiteral("true"));
  208.  
  209.     /* Write the modified panels out. */
  210.     this.datasource.QueryInterface(nsIRDFRemoteDataSource).Flush();
  211.  
  212. }
  213.  
  214. /* decorate prototype to provide ``class'' methods and property accessors */
  215. nsSidebar.prototype.addSearchEngine =
  216. function (engineURL, iconURL, suggestedTitle, suggestedCategory)
  217. {
  218.     debug("addSearchEngine(" + engineURL + ", " + iconURL + ", " +
  219.           suggestedCategory + ", " + suggestedTitle + ")");
  220.  
  221.     if (!this.window)
  222.     {
  223.         debug ("no window object set, bailing out.");
  224.         throw Components.results.NS_ERROR_NOT_INITIALIZED;
  225.     }
  226.  
  227.     try
  228.     {
  229.         // make sure using HTTP (for both engine as well as icon URLs)
  230.  
  231.         if (engineURL.search(/^http:\/\//i) == -1)
  232.         {
  233.             debug ("must use HTTP to fetch search engine file");
  234.             throw Components.results.NS_ERROR_INVALID_ARG;
  235.         }
  236.  
  237.         if (iconURL.search(/^http:\/\//i) == -1)
  238.         {
  239.             debug ("must use HTTP to fetch search icon file");
  240.             throw Components.results.NS_ERROR_INVALID_ARG;
  241.         }
  242.  
  243.         // make sure engineURL refers to a .src file
  244.         if (engineURL.search(/\.src$/i) == -1)
  245.         {
  246.             debug ("engineURL doesn't reference a .src file");
  247.             throw Components.results.NS_ERROR_INVALID_ARG;
  248.         }
  249.  
  250.         // make sure iconURL refers to a .gif/.jpg/.jpeg/.png file
  251.         if (iconURL.search(/\.(gif|jpg|jpeg|png)$/i) == -1)
  252.         {
  253.             debug ("iconURL doesn't reference a supported image file");
  254.             throw Components.results.NS_ERROR_INVALID_ARG;
  255.         }
  256.  
  257.     }
  258.     catch(ex)
  259.     {
  260.         this.window.alert("Failed to add the search engine.\n");
  261.         throw Components.results.NS_ERROR_INVALID_ARG;
  262.     }
  263.  
  264.     var titleMessage, dialogMessage;
  265.     try {
  266.         var stringBundle = srGetStrBundle("chrome://communicator/locale/sidebar/sidebar.properties");
  267.         var brandStringBundle = srGetStrBundle("chrome://global/locale/brand.properties");
  268.         if (stringBundle) {
  269.             sidebarName = brandStringBundle.GetStringFromName("sidebarName");            
  270.             titleMessage = stringBundle.GetStringFromName("addEngineConfirmTitle");
  271.             dialogMessage = stringBundle.GetStringFromName("addEngineConfirmMessage");
  272.             dialogMessage = dialogMessage.replace(/%title%/, suggestedTitle);
  273.             dialogMessage = dialogMessage.replace(/%category%/, suggestedCategory);
  274.             dialogMessage = dialogMessage.replace(/%url%/, engineURL);
  275.             dialogMessage = dialogMessage.replace(/#/g, "\n");
  276.             dialogMessage = dialogMessage.replace(/%name%/, sidebarName);
  277.         }
  278.     }
  279.     catch (e) {
  280.         titleMessage = "Add Search Engine";
  281.         dialogMessage = "Add the following search engine?\n\nName: " + suggestedTitle;
  282.         dialogMessage += "\nSearch Category: " + suggestedCategory;
  283.         dialogMessage += "\nSource: " + engineURL;
  284.     }
  285.           
  286.     var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
  287.     promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
  288.     var rv = promptService.confirm(this.window, titleMessage, dialogMessage);
  289.       
  290.     if (!rv)
  291.         return;
  292.  
  293.     var internetSearch = Components.classes[NETSEARCH_CONTRACTID].getService();
  294.     if (internetSearch)    
  295.         internetSearch = internetSearch.QueryInterface(nsIInternetSearchService);
  296.     if (internetSearch)
  297.     {
  298.         internetSearch.AddSearchEngine(engineURL, iconURL, suggestedTitle,
  299.                                        suggestedCategory);
  300.     }
  301. }
  302.  
  303. // property of nsIClassInfo
  304. nsSidebar.prototype.flags = nsIClassInfo.DOM_OBJECT;
  305.  
  306. // property of nsIClassInfo
  307. nsSidebar.prototype.classDescription = "Sidebar";
  308.  
  309. nsSidebar.prototype.QueryInterface =
  310. function (iid) {
  311.     if (!iid.equals(nsISidebar) && 
  312.         !iid.equals(nsIClassInfo) &&
  313.         !iid.equals(nsISupports))
  314.         throw Components.results.NS_ERROR_NO_INTERFACE;
  315.     return this;
  316. }
  317.  
  318. var sidebarModule = new Object();
  319.  
  320. sidebarModule.registerSelf =
  321. function (compMgr, fileSpec, location, type)
  322. {
  323.     debug("registering (all right -- a JavaScript module!)");
  324.     compMgr.registerComponentWithType(SIDEBAR_CID, "Sidebar JS Component",
  325.                                       SIDEBAR_CONTRACTID, fileSpec, location,
  326.                                       true, true, type);
  327. }
  328.  
  329. sidebarModule.getClassObject =
  330. function (compMgr, cid, iid) {
  331.     if (!cid.equals(SIDEBAR_CID))
  332.         throw Components.results.NS_ERROR_NO_INTERFACE;
  333.     
  334.     if (!iid.equals(Components.interfaces.nsIFactory))
  335.         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  336.     
  337.     return sidebarFactory;
  338. }
  339.  
  340. sidebarModule.canUnload =
  341. function(compMgr)
  342. {
  343.     debug("Unloading component.");
  344.     return true;
  345. }
  346.     
  347. /* factory object */
  348. sidebarFactory = new Object();
  349.  
  350. sidebarFactory.createInstance =
  351. function (outer, iid) {
  352.     debug("CI: " + iid);
  353.     if (outer != null)
  354.         throw Components.results.NS_ERROR_NO_AGGREGATION;
  355.  
  356.     return (new nsSidebar()).QueryInterface(iid);
  357. }
  358.  
  359. /* entrypoint */
  360. function NSGetModule(compMgr, fileSpec) {
  361.     return sidebarModule;
  362. }
  363.  
  364. /* static functions */
  365. if (DEBUG)
  366.     debug = function (s) { dump("-*- sidebar component: " + s + "\n"); }
  367. else
  368.     debug = function (s) {}
  369.  
  370. function getSidebarDatasourceURI(panels_file_id)
  371. {
  372.     try 
  373.     {
  374.         /* use the fileLocator to look in the profile directory 
  375.          * to find 'panels.rdf', which is the
  376.          * database of the user's currently selected panels. */
  377.         var directory_service = Components.classes[DIR_SERV_CONTRACTID].getService();
  378.         if (directory_service)
  379.             directory_service = directory_service.QueryInterface(Components.interfaces.nsIProperties);
  380.  
  381.         /* if <profile>/panels.rdf doesn't exist, get will copy
  382.          *bin/defaults/profile/panels.rdf to <profile>/panels.rdf */
  383.         var sidebar_file = directory_service.get(panels_file_id, Components.interfaces.nsIFile);
  384.  
  385.         if (!sidebar_file.exists())
  386.         {
  387.             /* this should not happen, as GetFileLocation() should copy
  388.              * defaults/panels.rdf to the users profile directory */
  389.             debug("sidebar file does not exist");
  390.             return null;
  391.         }
  392.  
  393.         debug("sidebar uri is " + sidebar_file.URL);
  394.         return sidebar_file.URL;
  395.     }
  396.     catch (ex)
  397.     {
  398.         /* this should not happen */
  399.         debug("caught " + ex + " getting sidebar datasource uri");
  400.         return null;
  401.     }
  402. }
  403.  
  404.  
  405. var strBundleService = null;
  406. function srGetStrBundle(path)
  407. {
  408.    var strBundle = null;
  409.    if (!strBundleService) {
  410.        try {
  411.           strBundleService =
  412.           Components.classes["@mozilla.org/intl/stringbundle;1"].getService(); 
  413.           strBundleService = 
  414.           strBundleService.QueryInterface(Components.interfaces.nsIStringBundleService);
  415.        } catch (ex) {
  416.           dump("\n--** strBundleService failed: " + ex + "\n");
  417.           return null;
  418.       }
  419.    }
  420.    strBundle = strBundleService.createBundle(path); 
  421.    if (!strBundle) {
  422.        dump("\n--** strBundle createInstance failed **--\n");
  423.    }
  424.    return strBundle;
  425. }
  426.  
  427.  
  428.