MozillaZine

Implementing XPCOM components in JavaScript

From MozillaZine Knowledge Base

(Difference between revisions)
Revision as of 21:37, 2 February 2006
Richwklein (Talk | contribs)
(About XPCOM)
<-- Previous diff
Revision as of 21:48, 2 February 2006
Richwklein (Talk | contribs)
(About XPCOM)
Next diff -->
Line 8: Line 8:
* XPCOM Drawbacks * XPCOM Drawbacks
-** Objects must be accessed from their defined interfaces. Javascript shortcuts such as the global window object annot be accessed.+** 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. *** 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 ** It is easier to have memory leaks
 +
 +== Finished Code ==
 +<pre>
 +
 +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";
 +
 +function MyPriority() {
 + this._priority = nsISupportsPriority.PRIORITY_LOWEST;
 +};
 +
 +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;
 + }
 +};
 +
 +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; }
 +};
 +
 +var MyPriorityFactory = {
 + 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; }
 +
 +</pre>

Revision as of 21:48, 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


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";

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

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;
  }
};

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; }
};

var MyPriorityFactory = {
  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; }