Neil's Place

About those labels

March 19th, 2008

After some recent newsgroup posts, I thought it might be a good idea to clarify how text is used in XUL.

XUL provides two elements for displaying text, <label> and <description>. The <label> element should be used when labelling a control or user interface element. It supports a control attribute which may be used to associate the label with another element, and an accesskey attribute to support a key shortcut for focusing the associated element.

The <description> element should be used for all other text in XUL. This element does not support the control or accesskey features.

Apart from that, both elements are the same, and are implemented the same.

There is, however, another characteristic that applies to both the <label> and <description> elements, and determines how the text is rendered.

One form involves placing the text inside the element as a child:

<label>Search:</label>

<description>Enter your login information</description>

The two lines of code above cause the elements to become CSS block elements. This text is displayed in the same way as that for displaying the text in web pages for instance, and supports things like breaking paragraphs into lines, drawing underlines, selection and spellcheck highlighting, and adjusting text as necessary to support right to left text, ligatures and various additional characteristics of certain languages. Thus, you can put whatever elements are allowed in a CSS block within these elements, for instance an html <br> element.

The second form is by using the value attribute:

<label value="Back"/>

<description value="Font Selection"/>

The code that implements this is different, is much simpler and doesn’t support line breaking – everything is rendered on one line – nor does it support selection and spellcheck highlighting or blinking text, although it does support other line decorations, and supports a crop attribute for displaying an ellipsis if there is not enough width available. The width is determined from the amount of text and the default height is determined from the height of the font. This type behaves more like a form control that happens to display read only text. In CSS terms, it would probably be considered a replaced element.

Usually, the most common purpose of using one over the other is to get wrapped text versus text that appears on one line. Naturally you would choose the ‘text as child’ form if you wanted more complex text and choose the ‘value attribute’ form for simple single line text. You would not choose which tag (<label> versus <description>) to use based on this criteria, although historically, many people have (incorrectly) done so. It doesn’t help of course that the XUL tutorial on XULPlanet says to do exactly that though. Boo.

To change the value in the first form with the text as a child, use the textContent property. To change the value in the attribute form, use the value property.

label.textContent = "New Text:";

label.value = "New Text";

Another common technique is to use a plain-styled read only <textbox> element:

<textbox class="plain" readonly="true"/>

This creates text which looks like a single line label or description, but allows selection and provides a context menu. This latter feature is really the only reason to use this form, so it should only be used when it is likely that the user will want to select the text. Specifically, the control and accesskey features won’t work, so you should not use this for labels.

You may see references in some documents to a <text> element. This element is an older element that should not be used. For historical reference, it is equivalent to a <description> element but only supports the value attribute form. Also, it doesn’t support any extra APIs so you should not use this element. I mention this because someone linked to a page which used the <text> element incorrectly. In fact, the author of that page had meant to use a different element, <textnode>, which is intended to be used in templates. Although it looks similar, the <textnode> element isn’t related to the description or label elements; instead it simply generates a DOM Text node in a template, which is useful when you want to use the text as child form:

<description><textnode value="?name"/></description>

This code generates output like the following when used in a template:

<description>Marian Dodson</description>

Do not adjust these margins

March 7th, 2008

An alert box in Mac OS X appears that says 'Fell short of minimum' if you enter a negative margin when using a custom page size

How to Break an Automated Popup Test

February 22nd, 2008

There are a set of automated tests used to check XUL menus and popups. These tests check to ensure that popups open and close in response to particular events, that the popups appear in the right location and that highlighting and navigation between menu items and submenus work correctly.

However, these tests tend to be very finicky in terms of when they decide to work properly. Usually they do, but they have a habit of breaking down when even a seemingly unrelated change in made. Compounding the problem is that frequently only one platform or even a specific machine will fail to run the tests properly, making the real issue difficult to diagnose. There are several cases where I’ve just guessed at a fix and got lucky, and several tests which have just been disabled since I can’t reproduce the problem locally. For others, the response when the tests fail is: “Look, Enn broke the tests again”.

Once a popup test fails, other tests will often fail as well. In this case, the usual cause is that a popup or a window is still open because the previous test failed, causing later tests, especially those that fire events, to be unable to work properly.

There are several reasons why the popup tests are so picky:

  • Popups cannot opened unless the window is focused. This prevents pages in background tabs, for instance, from displaying popups. However, it also means that the window must have the focus in order for a popup test to succeed. One trap here is that a new window is not focused until after the load event, which means that a popup opened during a load event may not open. Documents loaded in an existing window will be able to open popups within the load event as the existing window is already focused. This can cause problems if you’re not aware of it and don’t check the test in both circumstances, for instance if you just run one test individually versus running through the test suite.
  • Tooltips are opened when the mouse stops moving for a few moments and disappear when the mouse is moved again. The tooltip tests synthesize mouse movement events. This means however that while running a tooltip test, a spurious movement of the real mouse can cause additional events to fire, causing the test to fail as the tooltip either opens or closes at the wrong time. In fact, just having the mouse inside the window where the test is running can do this as well. The solution: move the mouse pointer somewhere else.
  • Some tests check for keyboard shortcuts on menus. Because the tests run inside a browser window, this can interfere with the shortcuts used by the browser itself, and vice versa. For instance, testing a particular key combination might open a browser menu, or activate a browser command, causing later tests to fail. Tricky to diagnose, as the test that fails might occur somewhat later than the key test. This issue isn’t unique to the menu tests though; any test which emulates the keyboard may have this issue. The keys tested in the current tests are carefully chosen to not conflict in this way, but only in English builds. If you are testing on another language, keyboard shortcuts may be different and you may have mysterious test failures.
  • The tests normally run in a little frame. Sometimes this frame isn’t large enough. This can be an issue if you are using a larger font for example. This can cause elements that the test uses, especially those tests that emulate mouse clicks, to be hidden. Since you can’t really click on an element that is scrolled offscreen, or because the coordinates may be different, the test can fail.
  • Some tests open a separate window to run, either because they need a top level chrome window, or because they need more space. Having a low screen resolution can cause these windows to open smaller than desired. As well, a lower resolution can cause popups to appear in different locations or smaller than expected, preventing tests from working properly.
  • The theme you are using can affect how the test runs. For instance, the addition of a one pixel border to an element can affect calculations, causing coordinates to be off by one.
  • Theme issues can also come up due to differences between platforms. One such case I discovered recently was due to a seemingly harmless rule in the default Windows theme:
      menubar > menu[_moz-menuactive="true"][open="true"] {
        border-width: 3px 1px 1px 3px;
      }

    This rule causes the border of a menu to change when the open attribute is set to true, which occurs while the popup is being opened. This has the side effect of causing a layout to occur to handle the new border, which in turn causes the popup to be made visible and the popupshown event to be fired. This is fine, but other platforms don’t have this style rule, so the layout to open the popup doesn’t occur until later, so the popupshown event which was being tested for fires at a different point.

These are some of the problems to be aware of when running the popup related tests, and many of these apply to other types of tests as well. If you are having problems with the tests, say on your own machine, (the popup tests are in the toolkit directory and are usually identified with a word like ‘popup’, ‘menu’ or ‘tooltip’ in their name), it may be worth checking if any of these problems apply.

Speaking of which…

February 9th, 2008

Hey, is that the XPCOM Reference on XULPlanet updated for Mozilla 1.9 and Firefox 3? Yeah, looks like it.

Future of XULPlanet

January 10th, 2008

We’ve been thinking a bit about the future of XULPlanet. developer.mozilla.org provides more documentation and is easier to update, both for me and for others, and also includes some of the documentation currently on XULPlanet. Due to the greater difficulty in keeping the XULPlanet version updated, this version of, for example, the tutorial, is a bit out of date.

To be honest, I haven’t updated XULPlanet documentation in quite some time, and probably won’t do much in the future. The only thing I’m likely to do is update the XPCOM reference once Firefox 3 arrives. Some developers prefer the XPCOM reference on XULPlanet instead of the MDC reference. However, the latter is created manually and is only partially complete. Perhaps someone with the time and inclination would offer to convert the XULPlanet Mozilla 1.8 XPCOM reference over to MDC. The scripts I used for this are also available.

XULPlanet at one time was quite useful, however, the time has come where its value no longer seems necessary. So at this stage, we have two options. Either find some way to make XULPlanet useful again, or remove it and have XULPlanet just redirect over to MDC.

Thoughts?

Toronto Conflict

November 2nd, 2007

We may just have to get Half-life 2 up here in the northern office just for this. The subway renditions alone are, as Mike Beltzner would say, sooooo awesome.

Menu and Popups Guide

July 26th, 2007

The Menu and Popups Guide is now available which provides detailed documentation on the XUL menu, context menu, panel and tooltip features as well as how to use them from script. Additional improvements are much appreciated, for instance more examples or images.

In other XUL popup news, I’ve been fixing a few regressions lately, as well as fixing some other long standing popup bugs. For Mozilla 1.9, we can look forward to being able to put decks and trees in a popup panel and have them actually work. I’ve also got a fix in hand for focus navigation in popups, so one can press Tab and cycle between elements without navigating outside the popup unexpectedly. Also, focus doesn’t get confused when a popup opens or closes.

XUL Popup Improvements

July 5th, 2007

The popup reworking patch finally made it in yesterday without any performance regressions. This features a number of improvements to the popup code.

  • Popups now open as well as fire events and change attributes asynchronously in some cases, making popups less crash prone.
  • Popups are kept track of better, avoiding the popups that hang on the screen and cannot be closed issue.
  • Some reflow improvements which make popups not jump about on the screen. Also, hopefully, the size of a popup or tooltip is determined properly, or at least more likely to be accurate.
  • Some decomtamination and removal of much duplicated code.
  • An openPopup and openPopupAtScreen method to use instead of the confusing showPopup. (showPopup is still supported though). The former opens a popup relative to another node while the latter opens a popup at a specific screen position.
  • A <panel> element is added which is designed for popups that are not menus. XUL didn’t offically support this before. <menupopup> should be used for menus and <tooltip> for tooltips. The <popup> element is deprecated (as has always been the case) and is equivalent to <menupopup>.

There’s still some work to be done with popups. For instance, focus navigation in popups is a bit broken. This could be a tricky fix as it requires fixing some focus code while avoiding becoming the focus module owner.

Testing of popups is much appreciated. I know about the tooltips in html being the wrong size issue. The fix for this is to remove a workaround so that’s a good thing.

Tasks to Complete

May 29th, 2007

There’s lots of changes to XUL in Mozilla 1.9. Some of these are documented already in the XUL element reference, but expect some more documentation in the future. But there’s still some things I want to get done for Mozilla 1.9:

  • The XUL Popup reworking fixes a pile of bugs, makes popups less crash prone, and avoids the issue of popups that seem to hang around on the screen. It adds a <panel> element which is a type of popup designed for non-menu content so the keyboard works properly within it. Also, the API for opening popups is modified to be more useful and well defined. Much XPCOM overhead is removed too.
  • Template with XML Sources support is almost ready. After that, a couple of fairly simple improvements to support reading other types of data (currently being worked on by Laurent Jouanneau), and logging so that debugging a template is possible. However, the last feature I have in mind, nested templates, will likely have to wait.
  • Robert O’Callahan is almost finished up his patch for supporting getBoundingClientRect and getClientRects. These two functions allow one to get the area of an element as well as the rectangles used for text. I’d also like to support the offset and scroll properties in XUL. This allows us to move away from using the underspecified Mozilla specific box object APIs and move towards the er, um, underspecified Microsoft APIs. But the latter is at least being working on as a specification.
  • I have a working WHAT-WG drag and drop implementation in bug 356295 with a few extra features needed for XUL use. However, this probably won’t be able to be in 1.9.
  • After adding support for optional arguments in IDL to make things easier, the Scriptable IO support will be almost finished. This will make it easier to handle files and other streams from extensions. Unfortunately, the existing APIs were really designed for asynchronous network usage, so I may end up needing to reimplement some of the text reading and writing code so that things make more sense.
  • No additional XUL elements are planned besides the ones aready checked in, but there is some polish still to go, along with lots of XUL tests.

Scriptable IO

May 9th, 2007

So one thing that is hard to do in Mozilla is read and write to files. This invoves a lot of creating of XPCOM components, initializing them and wrapping them in various other streams components. Or, you could use a library like jslib or similar. But it doesn’t have to be that way. What if an easier method was built-in:

// write a string to the file stuff.txt from the Home directory.
var file = IO.newFile("Home", "stuff.txt");
var stream = IO.newOutputStream(file, "text");
stream.writeString("This is a file\n");
stream.close();

And what if a similar technique could be used for reading and writing from files, sockets or other streams? What if this was reality?

See Scriptable IO for more details. Comments very welcome, especially on the API.