Changes

Jump to: navigation, search

Real World Mozilla Adding Chrome to FirstXpcom Lab

632 bytes added, 16:22, 23 March 2007
no edit summary
=Introduction=
Previously we created an XPCOM component called [[Dive into Mozilla First XPCOM Component|FirstXpcom]], tested it in the [[Dive into Mozilla First XPCOM Component#Accessing FirstXpcom from the JavaScript Shell|JavaScript Shell]], and [[Dive into Mozilla Unit Testing Lab|wrote xpcshell unit tests]]. However, we haven't really done anything with it yet. Ideally we'd like to add our component to the browser and create some UI in order to allow the user to access its functionality.
We'll work in stages to create a simple UI for accessing FirstXpcom, first as a separate chrome extension, before integrating it with the build system. Our goal will be to add a custom dialog box to the browser, accessible via the menu bar. This dialog box will allow the user to access the functionality in our XPCOM component via JavaScript that we'll write.
== Generating the extension automatically ==
We've now gone through the process of [http://developer.mozilla.org/en/docs/Building_an_Extension creating an extension] by hand twice (e.g., writing install.rdf, creating the proper directory structure, etc.), so we won't cover the process again. Instead, we'll use a handy [http://ted.mielczarek.org/code/mozilla/extensionwiz/ on-line wizard] to do the work for us. Use the following values/optionsin the [http://ted.mielczarek.org/code/mozilla/extensionwiz/ wizard]:
* '''Your Name:''' ''Your Name''
* '''Target Applications''' Firefox Minimum Version=2.0.0.* Maximum Version=3.0a3pre
After clicking '''Click Create Extension''', navigate to your desktop and locate the generated file, '''firstxpcomchrome.zip'''. Extract this file somewhere (e.g., '''c:\temp\firstxpcomchrome''').
Now create a file in your profile's extension folder (%Application Data%\Mozilla\Firefox\Profile\''<development_profile>''\extensions) named '''firstxpcomchrome@senecac.on.ca'''. This file should contain the full path to your unzipped extension (perhaps '''c:\temp\firstxpcomchrome'''). Here is one way to do it:
$ cd Application\ Data/Mozilla/Firefox/Profiles/''development_profile''/extensions
== Exploring the other generated files ==
The [http://ted.mielczarek.org/code/mozilla/extensionwiz/ extension wizard] also generated [http://developer.mozilla.org/en/docs/Localization localization ] code, which you can see being used abovebelow, for example:
<pre>
</pre>
The property itself, which modifies '''firstxpcomchrome-hello''' , is defined as follows:
<pre>
</pre>
Using skins [http://developer.mozilla.org/en/docs/Themes themes] and [http://developer.mozilla.org/en/docs/Localization localization ] are topics in their own right. We'll discuss them again in future labs.
== Adding our own code ==
The '''firefoxOverlay.xul''' file specifies that when the menu item is clicked, the '''firstxpcomchrome.onMenuItemCommand''' method will be called:
<pre>
</pre>
This is perfect for our needs. It means that we need to add our code to '''firstxpcomchrome.onMenuItemCommand''' and it will be called a at the appropriate time.
Here is '''firstxpcomchrome/content/overlay.js''':
</pre>
Let's begin with the final line, a load listener which insures that our code is run when the browser starts-up. Our object's '''onLoad''' function takes care of general initialization tasks, including creating an instance of '''FirstXpcom''' that we'll use throughout the life of our extension:
firstxpcom: null,
this.firstxpcom.name = "First XPCOM";
Just as we did in our [[Dive into Mozilla Unit Testing Lab|unit tests ]] and with the [[Dive into Mozilla First XPCOM Component#Accessing FirstXpcom from the JavaScript Shell|JS Shell]], we create an instance of '''firstxpcom''' and then QI (i.e., ''"query interface"'') it to '''IFirstXpcom'''. Now we can call its methods, for example, setting the '''name''' attribute. We do the same later in '''onMenuCommand''':
this.total = this.'''firstxpcom.add'''(this.total, result.value);
false, "", null);
I chose to use the [http://developer.mozilla.org/en/docs/nsIAlertsService nsIAlertsService] , which creates an animated pop-up over the task list, rather than displaying the info to the user with an alert() , for a number of reasons. First, I want to show that now that you know how to create an XPCOM component in C++, and also how to use it in JavaScript, you can use any of the [http://developer.mozilla.org/en/docs/Interfaces hundreds of objects and interfaces] available in the Mozilla platform--the nsIAlertsService is no different from IFirstXpcom. I also wanted to draw your attention to another method of instantiating a component in JavaScript. Compare the following two code snippets:
this.firstxpcom = Components.classes["@senecac.on.ca/firstxpcom;1"]
.'''getService'''(Components.interfaces.nsIAlertsService);
In the former case we use '''createInstance''', which gives us a new unique instance. In the latter , we use '''getService''', which returns a shared instance of an existing component (i.e., a Singleton). Unlike IFirstXpcom, which can be created many times by different callers, the nsIAlertsService is a shared component, because only one pop-up message at a time can be shown to the user.
<blockquote>NOTE: Because this is JavaScript and not C++, there is no need to recompile or start/stop the browser when you make a change to your files. Using the [http://ted.mielczarek.org/code/mozilla/extensiondev/index.html Extension Developer's extension], you can simply reload all chrome: '''Tools > Extension Developer > Reload All Chrome'''</blockquote>
</pre>
When the menu item is clicked, the dialog will be shown and the values the user enters returned. The '''showDialog''' function begins by packaging up IN ''in'' (we use '''inn''' because '''in''' is a keyword in JavaScript) and OUT ''out'' variables. This allows us to pass multiple variables from/to the dialog. In this case, we pass the value of our component's '''name''' attribute to the dialog, so it can be displayed in a textbox for editing. The '''out''' variable will contain the updated values as entered in the dialog's textboxes (the code to do this will be discussed shortly).
We actually display the dialog using '''window.openDialog''', which takes a URI to our dialog's XUL file, as well as a list of options (e.g., dialog is modal, resizable, etc.) and our '''params''' object, containing the inn and out variables. Execution will block on '''focus()''' until the user clicks OK or Cancel, or closes the window.
</pre>
In the '''dialog ''' element we've wired the '''onLoad''' and '''onOK''' functions. The '''onLoad''' function is used to extract the parameters passed in with the call to '''window.openDialog()''' and then set values in the UI.
The '''onOK''' function occurs when the user clicks the accept button (i.e., OK). When this happens the values from the textboxes are obtained and packaged up in the '''out''' parameter we sent in earlier. This is how we pass values back to the main window, and our extension code in '''firstxpcomchrome'''.
= Integrating with the build systetm =
'''TODO ''' -- see http://developer.mozilla.org/en/docs/JAR_Manifests for a discussion of jar.mn files in the build system.
=Reflections=
We've now gone through a complete cycle, first developing a C++ XPCOM component, then writing [[Dive into Mozilla Unit Testing Lab|unit tests ]] and throw-away code in the [[Dive into Mozilla First XPCOM Component#Accessing FirstXpcom from the JavaScript Shell|JavaScript shell]], before finally creating a complete XUL/JS extension with a custom UI. The lessons learned along the way are useful even if you don't plan on doing all of it again: C++ developers have gained an awareness of the types of issues XUL/JS developers will face; and XUL/JS developers have a better understanding of what is happening when they use components and interfaces through script.
This simple component and extension can be used as the foundation for your next extension project. We've really only scratched the surface.
=Resources=

Navigation menu