MozillaZine

Implementing XPCOM components in JavaScript

From MozillaZine Knowledge Base

(Difference between revisions)
Revision as of 21:48, 2 February 2006
Richwklein (Talk | contribs)
(About XPCOM)
<-- Previous diff
Revision as of 21:51, 2 February 2006
Richwklein (Talk | contribs)
(Finished Code)
Next diff -->
Line 13: Line 13:
== Finished Code == == Finished Code ==
 +Below is how the finished code may look.
 +
<pre> <pre>
 +// constants
const nsISupportsPriority = Components.interfaces.nsISupportsPriority; const nsISupportsPriority = Components.interfaces.nsISupportsPriority;
const CLASS_ID = Components.ID("{1C0E8D86-B661-40d0-AE3D-CA012FADF170}"); const CLASS_ID = Components.ID("{1C0E8D86-B661-40d0-AE3D-CA012FADF170}");
Line 20: Line 23:
const CONTRACT_ID = "@mozillazine.org/example/priority;1"; const CONTRACT_ID = "@mozillazine.org/example/priority;1";
 +//class constructor
function MyPriority() { function MyPriority() {
this._priority = nsISupportsPriority.PRIORITY_LOWEST; this._priority = nsISupportsPriority.PRIORITY_LOWEST;
}; };
 +//class definition
MyPriority.prototype = { MyPriority.prototype = {
_priority: null, _priority: null,
Line 43: Line 48:
}; };
 +//class factory
 +var MyPriorityFactory = {
 + createInstance: function (aOuter, aIID)
 + {
 + if (aOuter != null)
 + throw Components.results.NS_ERROR_NO_AGGREGATION;
 + return (new MyPriority()).QueryInterface(aIID);
 + }
 +};
 +
 +//module definition (xpcom registration)
var MyPriorityModule = { var MyPriorityModule = {
_firstTime: true, _firstTime: true,
Line 75: Line 91:
}; };
-var MyPriorityFactory = {+//module initialization
- createInstance: function (aOuter, aIID)+
- {+
- if (aOuter != null)+
- throw Components.results.NS_ERROR_NO_AGGREGATION;+
- return (new MyPriority()).QueryInterface(aIID);+
- }+
-};+
- +
function NSGetModule(aCompMgr, aFileSpec) { return MyPriorityModule; } function NSGetModule(aCompMgr, aFileSpec) { return MyPriorityModule; }
</pre> </pre>

Revision as of 21:51, 2 February 2006

About XPCOM

Mozilla applications are built from a collection of XPCOM (Cross-platform Component Object Model) objects. They are used to perform certain tasks or to get specific functionality. For example, there is a directory service component that can be used to access files on your file system. Components can be constructed using several programming languages, including: javascript, c++, and python. Mozilla then uses "interfaces" to describe what a component can do. The most basic interface nsISupports is used to get different interfaces that a component implements.

  • Benifits of XPCOM
    • XPCOM objects can be used by any programming language mozilla supports.
    • Objects implemented as XPCOM are global to an application, and are not dependent on the scope of any one window.
    • Programming logic can be encapsulated within an object.
  • XPCOM Drawbacks
    • Objects must be accessed from their defined interfaces. Javascript shortcuts such as the global window object cannot be accessed.
      • The only exception to this rules, is if you set a magical property wrappedJSObject equal to your component, then the underlining javascript object can be accessed.
    • It is easier to have memory leaks

Finished Code

Below is how the finished code may look.


// constants
const nsISupportsPriority = Components.interfaces.nsISupportsPriority;
const CLASS_ID = Components.ID("{1C0E8D86-B661-40d0-AE3D-CA012FADF170}");
const CLASS_NAME = "My Supports Priority Component";
const CONTRACT_ID = "@mozillazine.org/example/priority;1";

//class constructor
function MyPriority() {
  this._priority = nsISupportsPriority.PRIORITY_LOWEST;
};

//class definition
MyPriority.prototype = {
  _priority: null,

  get priority() { return this._priority; },
  set priority(aValue) { this._priority = aValue; },

  adjustPriority: function(aDelta) {
    this._priority += aDelta;
  },

  QueryInterface: function(aIID)
  {
    if (!aIID.equals(nsISupportsPriority) &&    
        !aIID.equals(Components.interfaces.nsISupports))
      throw Components.results.NS_ERROR_NO_INTERFACE;
    return this;
  }
};

//class factory
var MyPriorityFactory = {
  createInstance: function (aOuter, aIID)
  {
    if (aOuter != null)
      throw Components.results.NS_ERROR_NO_AGGREGATION;
    return (new MyPriority()).QueryInterface(aIID);
  }
};

//module definition (xpcom registration)
var MyPriorityModule = {
  _firstTime: true,
  registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
  {
    if (this._firstTime) {
      this._firstTime = false;
      throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
    };
    aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, CONTRACT_ID, aFileSpec, aLocation, aType);
  },

  unregisterSelf: function(aCompMgr, aLocation, aType)
  {
    aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);        
  },
  
  getClassObject: function(aCompMgr, aCID, aIID)
  {
    if (!aIID.equals(Components.interfaces.nsIFactory))
      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;

    if (aCID.equals(CLASS_ID))
      return MyPriorityFactory;

    throw Components.results.NS_ERROR_NO_INTERFACE;
  },

  canUnload: function(aCompMgr) { return true; }
};

//module initialization
function NSGetModule(aCompMgr, aFileSpec) { return MyPriorityModule; }