238 lines
8.3 KiB
JavaScript

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): Stephen Lamm <slamm@netscape.com>
*/
/*
* No magic constructor behaviour, as is de rigeur for XPCOM.
* If you must perform some initialization, and it could possibly fail (even
* due to an out-of-memory condition), you should use an Init method, which
* can convey failure appropriately (thrown exception in JS,
* NS_FAILED(nsresult) return in C++).
*
* In JS, you can actually cheat, because a thrown exception will cause the
* CreateInstance call to fail in turn, but not all languages are so lucky.
* (Though ANSI C++ provides exceptions, they are verboten in Mozilla code
* for portability reasons -- and even when you're building completely
* platform-specific code, you can't throw across an XPCOM method boundary.)
*/
const DEBUG = true; /* set to false to suppress debug messages */
const PANELS_RDF_FILE = 66626; /* the magic number to find panels.rdf */
const SIDEBAR_PROGID = "component://mozilla/sidebar";
const SIDEBAR_CID = Components.ID("{22117140-9c6e-11d3-aaf1-00805f8a4905}");
const CONTAINER_PROGID = "component://netscape/rdf/container";
const LOCATOR_PROGID = "component://netscape/filelocator";
const nsISupports = Components.interfaces.nsISupports;
const nsIFactory = Components.interfaces.nsIFactory;
const nsISidebar = Components.interfaces.nsISidebar;
const nsIRDFContainer = Components.interfaces.nsIRDFContainer;
const nsIFileLocator = Components.interfaces.nsIFileLocator;
const nsIRDFRemoteDataSource = Components.interfaces.nsIRDFRemoteDataSource;
function nsSidebar()
{
const RDF_PROGID = "component://netscape/rdf/rdf-service";
const nsIRDFService = Components.interfaces.nsIRDFService;
this.rdf = Components.classes[RDF_PROGID].getService(nsIRDFService);
this.datasource_uri = getSidebarDatasourceURI(PANELS_RDF_FILE);
debug('datasource_uri is ' + this.datasource_uri);
this.resource = 'urn:sidebar:current-panel-list';
this.datasource = this.rdf.GetDataSource(this.datasource_uri);
}
nsSidebar.prototype.nc = "http://home.netscape.com/NC-rdf#";
nsSidebar.prototype.setWindow =
function (aWindow)
{
this.window = aWindow;
}
nsSidebar.prototype.isPanel =
function (aContentURL)
{
var container =
Components.classes[CONTAINER_PROGID].createInstance(nsIRDFContainer);
container.Init(this.datasource, this.rdf.GetResource(this.resource));
/* Create a resource for the new panel and add it to the list */
var panel_resource =
this.rdf.GetResource("urn:sidebar:3rdparty-panel:" + aContentURL);
return (container.IndexOf(panel_resource) != -1);
}
/* decorate prototype to provide ``class'' methods and property accessors */
nsSidebar.prototype.addPanel =
function (aTitle, aContentURL, aCustomizeURL)
{
debug("addPanel(" + aTitle + ", " + aContentURL + ", " +
aCustomizeURL + ")");
if (!this.window)
{
debug ("no window object set, bailing out.");
throw Components.results.NS_ERROR_NOT_INITIALIZED;
}
/* Create a "container" wrapper around the
* "urn:sidebar:current-panel-list" object. This makes it easier
* to manipulate the RDF:Seq correctly. */
var container =
Components.classes[CONTAINER_PROGID].createInstance(nsIRDFContainer);
container.Init(this.datasource, this.rdf.GetResource(this.resource));
/* Create a resource for the new panel and add it to the list */
var panel_resource =
this.rdf.GetResource("urn:sidebar:3rdparty-panel:" + aContentURL);
var panel_index = container.IndexOf(panel_resource);
if (panel_index != -1)
{
this.window.alert(aContentURL + " already exists in your sidebar.");
return;
}
var rv = this.window.confirm("Add " + aContentURL + " to your sidebar?");
if (!rv)
return;
this.datasource.Assert(this.rdf.GetResource(this.resource),
this.rdf.GetResource(this.nc + "inbatch"),
this.rdf.GetLiteral("true"),
true);
/* Now make some sidebar-ish assertions about it... */
this.datasource.Assert(panel_resource,
this.rdf.GetResource(this.nc + "title"),
this.rdf.GetLiteral(aTitle),
true);
this.datasource.Assert(panel_resource,
this.rdf.GetResource(this.nc + "content"),
this.rdf.GetLiteral(aContentURL),
true);
if (aCustomizeURL)
this.datasource.Assert(panel_resource,
this.rdf.GetResource(this.nc + "customize"),
this.rdf.GetLiteral(aCustomizeURL),
true);
container.AppendElement(panel_resource);
this.datasource.Unassert(this.rdf.GetResource(this.resource),
this.rdf.GetResource(this.nc + "inbatch"),
this.rdf.GetLiteral("true"));
/* Write the modified panels out. */
this.datasource.QueryInterface(nsIRDFRemoteDataSource).Flush();
}
var sidebarModule = new Object();
sidebarModule.registerSelf =
function (compMgr, fileSpec, location, type)
{
debug("registering (all right -- a JavaScript module!)");
compMgr.registerComponentWithType(SIDEBAR_CID, "Sidebar JS Component",
SIDEBAR_PROGID, fileSpec, location,
true, true, type);
}
sidebarModule.getClassObject =
function (compMgr, cid, iid) {
if (!cid.equals(SIDEBAR_CID))
throw Components.results.NS_ERROR_NO_INTERFACE;
if (!iid.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
return sidebarFactory;
}
sidebarModule.canUnload =
function(compMgr)
{
debug("Unloading component.");
return true;
}
/* factory object */
sidebarFactory = new Object();
sidebarFactory.CreateInstance =
function (outer, iid) {
debug("CI: " + iid);
if (outer != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
if (!iid.equals(nsISidebar) && !iid.equals(nsISupports))
throw Components.results.NS_ERROR_INVALID_ARG;
return new nsSidebar();
}
/* entrypoint */
function NSGetModule(compMgr, fileSpec) {
return sidebarModule;
}
/* static functions */
if (DEBUG)
debug = function (s) { dump("-*- sidebar: " + s + "\n"); }
else
debug = function (s) {}
function getSidebarDatasourceURI(panels_file_id)
{
try
{
/* use the fileLocator to look in the profile directory
* to find 'panels.rdf', which is the
* database of the user's currently selected panels. */
var fileLocatorService =
Components.classes[LOCATOR_PROGID].getService(nsIFileLocator);
/* if <profile>/panels.rdf doesn't exist, GetFileLocation() will copy
*bin/defaults/profile/panels.rdf to <profile>/panels.rdf */
var sidebar_file = fileLocatorService.GetFileLocation(panels_file_id);
if (!sidebar_file.exists())
{
/* this should not happen, as GetFileLocation() should copy
* defaults/panels.rdf to the users profile directory */
debug("sidebar file does not exist");
return null;
}
debug("sidebar uri is " + sidebar_file.URLString);
return sidebar_file.URLString;
}
catch (ex)
{
/* this should not happen */
debug("caught " + ex + " getting sidebar datasource uri");
return null;
}
}