Posts Tagged ‘firefox’

Articles

Using dialogs and menulists on Fennec

In Uncategorized on March 10, 2010 by marioalv2 Tagged: , , ,

I was assigned a task to develop a Reporter Mechanism for Fennec, the mobile version of Firefox.
There are some key differences between coding an add-on for Fennec and for Firefox, but I’ll better let Mark Finkle explain them on his blog.

Now, for my developing of the Reporter Mechanism for Fennec, there are some points that I learned and I would like to share, in case someone gets in trouble dealing with the aspects I dealt with.

This experienced is described in the following.

Dealing with a menulist

One of the requirements of the Reporter was to present the user a menulist with problem categories, so he could pick one category and include it in his report.
Reporter-Menulist

Figure 1. The Reporter add-on and its menulist with problem categories

So, as a newbie Fennec developer, I created the reporter pop up window with a menulist element and expected it to work fine:

<vbox id="reporter-create-report-container" class="dialog-dark"
      hidden="true" top="0" left="0" width="0px">
  ...
    <menulist id="reporter-problem-categories-list" class="button-dark"
                 onclick="ReporterForFennec.hide()"
                 oncommand="ReporterForFennec.show()">
      <menupopup id="reporter-problem-categories-list-popup">
        <menuitem label="&reportForm.problem_type.item1.title;" value="1"/>
      ...
      </menupopup>
    </menulist>
   ...
</vbox>

Some notes about this code:

  • According to Fennec’s best practices article and after reading some Fennec’s source code, you should develop your dialog as a hidden box and show it whenever it’s necessary. This part of the code was OK, I followed the rule
  • Don’t pay attention to the top=”0″ left=”0″ width=”0px”, because I resized and centered the dialog programatically when I showed it
  • I had a set of show() and hide() functions, so when the user clicked on the menulist, the reporter dialog disappeared ( onclick=”ReporterForFennec.hide() ) and when the user clicked on the menulist “Done” button, the reporter dialog reappeared again ( oncommand=”ReporterForFennec.show() ). This part was not OK, it needed some corrections
  • This code doesn’t work fine. Why?
    • Let’s say I showed the reporter dialog window and clicked on the menulist
    • The menulist appears
    • I choose an option and click the “Done” button
    • The reporter window was expected to appear again, but…
    • There was a problem with this interaction: if the menulist was shown and the user didn’t change the selected option, the reporter dialog didn’t appear again as expected

So I went to ask on the mozilla #mobile IRC channel how could I solve this problem, and they gave me the solution:

<vbox id="reporter-create-report-container" class="dialog-dark" hidden="true"
      insertbefore="select-container" top="0" left="0" width="0px">

Do you see the new insertbefore=”select-container” attribute in the reporter dialog?
Since the reporter dialog depended on the “select-container” element (Fennec’s UI for the menulist and select widgets), the reporter dialog could not be higher in the z-order hierarchy of Fennec elements.
After implementing the solution, I got rid of the onclick and on command attributes of the menulist.
This was the resulting and working code:

<vbox id="reporter-create-report-container" class="dialog-dark" hidden="true"
      insertbefore="select-container" top="0" left="0" width="0px">
  ...
    <menulist id="reporter-problem-categories-list" class="button-dark">
      <menupopup id="reporter-problem-categories-list-popup">
        <menuitem label="&reportForm.problem_type.item1.title;" value="1"/>
        ...
      </menupopup>
    </menulist>
   ...
</vbox>

After finishing with the menulist interaction, another problem surfaced.  I describe this new problem next.

Dealing with a dialog window and the “click to dismiss” functionality

Another of the Reporter requirements was to make the reporter dialog disappear whenever the user clicked outside of the dialog (this is what we call the “click to dismiss” functionality).
Reporter-Hidden

Figure 2. The Reporter dialog disappears when the user clicks outside the dialog

At this point I had the Reporter dialog interacting fine with the menulist, but the dialog didn’t disappear whenever the user clicked outside of it.
So, in order to make the Reporter dialog disappear when the user clicks outside of it, I also had a struggling / go ask on IRC / test your code life cycle in which I came up with this code:

overlay.xul:

<vbox id="identity-container">
  ...
    <hbox id="reporter-container" align="center" pack="center">
      <button id="reporter-create-report-button" class="button-dark"
              label="&reportForm.buttonLabels.reportProblem;" align="center"
              oncommand="ReporterForFennec.show();"/>
    </hbox>
  ...
</vbox>

overlay.js:

ReporterForFennec = {

  _cacheElements
  {
   ...
   this._reporterCreateReportContainer = document.getElementById('reporter-create-report-container');
   this._selectContainer = document.getElementById('select-container');
  },

  show: function(aEvent)
  {
   ...
   this._reporterCreateReportContainer.hidden = false;
   ...
   BrowserUI.pushPopup(this, [this._reporterCreateReportContainer, this._selectContainer]);
  },

  hide: function(aEvent)
  {
   this._reporterCreateReportContainer.hidden = true;
   ...
   BrowserUI.popPopup();
  },
}

Some notes about this code:

  • You need to have an object that implements a hide() method (and preferably a show() method). The hide() method will be called when a click happens somewhere on the UI and your dialog needs to disappear. In this case, the object that implemented the hide() method was the ReporterForFennec object
  • BrowserUI.pushPopup(aPanel, aElements) method can be called from anywhere in your code.
    I call BrowserUI.pushPopup(aPanel, aElements) in my show() method because I need to tell Fennec which elements I can click on and won’t disappear every time when I show my reporter dialog
  • The first argument for BrowserUI.pushPopup(aPanel, aElements) is the Javascript object that implements the hide() method that is called when a click happens outside your dialog and your dialog needs to disappear
  • The second argument for BrowserUI.pushPopup(aPanel, aElements) can be an array of nodes or just a simple DOM node. The aElements nodes are the elements that you can click on and won’t disappear when showing your dialog. In this case, the array contained a reference to the Reporter dialog and the menulist UI element
  • Inside the hide() method you need to call the BrowserUI.popPopup() so the internal stack of visual of elements gets balanced

All these combined ingredients made the Reporter dialog disappear when the user clicked outside of it, and stay on screen when the user clicked inside of it or inside the dialog’s corresponding menulist.

Those were the main two problems I faced on my first Fennec development. As you can see, dealing with dialogs can get a little tricky if you are an unexperienced Fennec developer like me.  That’s why I wanted to share my experience hoping this writing can help anyone dealing with the same problems I did.

I would also like to thank Aakash for his guidance in this Reporter project and the guys from the mozilla #mobile IRC channel for all the help provided during this development, specially mfinkle, fabrice and vingtetun.