Mike Kaply has asked me over IRC to detail how I made the webchunk icon float over a document. Here's my answer...

It's a tricky probem I already solved many years ago in c++ when I added the resizers and the inline table editing elements to the editor. Unfortunately, what I did at that time is not directly reusable in JS because SetNativeAnonymous() is not scriptable.

So what do we need here :

  1. we need to make an arbitrary element float over a document in a browser or iframe
  2. that element should scroll with the viewport, it's not fixed
  3. it should be positionable relatively to any other element
  4. it should appear when the pointer hovers over a certain type of element and be clickable
  5. table layout is broken is we add anonymous elements in a table...

We can draw immediate conclusions:

  1. the floater must be a child of the body
  2. we need a way to make the icon remain onscreen when the mouse pointer leaves the originating element to the icon

Let's take the example of webslices. We need to make the icon appear when the mouse pointer hovers over slices (elements having an ID and the hslice class). The CSS selector we're going to use is then:


And we're going to use that selector to attach a binding to those elements.

@namespace url('http://www.w3.org/1999/xhtml');
*[class*='hslice'][id]:hover { -moz-binding: url('chrome://webchunks/content/webchunk.xml#webchunk'); }

But there's a bug here in Gecko. This CSS rule should apply only on :hover, and the default binding should be -moz-binding: none when the mouse does NOT hover over the element. As a workaround for that bug, we unfortunately need another binding...

*[class*='hslice'][id]:not(:hover) { -moz-binding: url('chrome://webchunks/content/webchunk.xml#unwebchunk'); }

Yeah, that's ugly, but that's all we can do. Since the floating icon needs to be a child of the body, we also need a binding for the body.

body { -moz-binding: url('chrome://webchunks/content/webchunk.xml#bodywebchunk'); }

But wait, that's not enough... You want the floating icon to be active, so we need bindings for it too...

*[anonid='webchunkIcon']:hover { -moz-binding: url('chrome://webchunks/content/webchunk.xml#webchunkIcon'); }
*[anonid='webchunkIcon']:not(:hover) { -moz-binding: url('chrome://webchunks/content/webchunk.xml#unwebchunkIcon'); }

When do we apply that styles ? When the pageshow event is fired. So my XUL overlay has something like:

window.addEventListener('load',   webchunks.init, false);

and webchunks.init() has itself

var tb = document.getElementById("content");
tb.addEventListener("pageshow",   webchunks.onPageShow, false);

while webchunks.onPageShow() does the following. Don't miss the event listener added at the bottom of that code.

@namespace url('http://www.w3.org/1999/xhtml'); \
body { \
-moz-binding: url('chrome://webchunks/content/webchunk.xml#bodywebchunk'); \
} \
*[class*='hslice'][id]:hover { \
-moz-binding: url('chrome://webchunks/content/webchunk.xml#webchunk'); \
} \
*[class*='hslice'][id]:not(:hover) { \
-moz-binding: url('chrome://webchunks/content/webchunk.xml#unwebchunk'); \
} \
*[anonid='webchunkIcon']:hover { \
-moz-binding: url('chrome://webchunks/content/webchunk.xml#webchunkIcon'); \
} \
*[anonid='webchunkIcon']:not(:hover) { \
-moz-binding: url('chrome://webchunks/content/webchunk.xml#unwebchunkIcon'); \

  onPageShow: function webchunks_onPageShow(aEvent)
    // find the current browsed document
    var browser = getBrowser();
    var doc = browser.contentDocument;
    if (!doc)
    if (doc &&
        doc.contentType &&
        doc.contentType != "text/html" &&
        doc.contentType != "application/xhtml+xml")
    // at this point, we're sure to have an (X)HTML document
    try {
      var head = doc.getElementsByTagName("head");
      if (head && head.length)
        var linkElt = doc.createElement("style");
        var t = doc.createTextNode(webchunks.kWEBCHUNK_STYLESHEET);
// we want to detect clicks on the floating icon
        getBrowser().addEventListener("click", webchunks.onFloaterClick, true);
    catch(e) {
      dump(e + (typeof e.stack == "string" ? ("\n" + e.stack) : "") + "\n\n");

What's the binding for our body element now ? It's a trivial one :

  <binding id="bodywebchunk">
      <html:img src="chrome://webchunks/skin/webchunk.png"
                style="display: none; position: absolute; top: 0px; left: 0px;"/>
      <field name="mHovered">null</field>
      <property name="mWebchunkIcon">
          return document.getAnonymousElementByAttribute(this, "anonid", "webchunkIcon");

Really nothing  special here. The content model appends an anonymous HTML image to the body, and it's originally hidden. The only important thing is the mHovered field, that we need to store the originating webslice element when the mouse pointer moves from the element to the floater. Let's now look at the main bindings starting by the one for the webslices. That's the one on :hover :

  <binding id="webchunk">
          var x = 0, y = 0;
          var elt = this;
          while (elt)
            x = x + elt.offsetLeft;
            y = y + elt.offsetTop;
            elt = elt.offsetParent;
          var image = document.body.mWebchunkIcon;
          image.style.top = y + "px";
          image.style.left = Math.max(0, x - 28) + "px";
          image.style.display = "inline";
          image.style.visibility = "visible";
          this.style.outline = "thin ridge rgb(186,154,236)";
          document.body.mHovered = this;
          image.mSlice = this;

When the binding is applied, we position the icon, make it appear, and store a ref to the originating element in the icon and the body. When the mouse leaves the element, we use the other binding :

  <binding id="unwebchunk">
        this.style.outline = "";
        setTimeout(this.hideChunkIcon, 200, this);
      <method name="hideChunkIcon">
        <parameter name="slice"/>
        if  (document.body.mHovered == slice)
          document.body.mWebchunkIcon.style.visibility = 'hidden';

Remember this binding is applied only when the mouse pointer is NOT hovering over the element. So the constructor gives a little delay so the user can move the pointer to the floating icon. After that delay, and if the mHovered field of the body was NOT modified by the floating icon, the icon goes away. At this point, you certainly got the trick. Here's the main binding for the icon :

  <binding id="webchunkIcon">
        document.body.mHovered = this;
     <field name="mSlice">null</field>

The icon notifies the body it now has the pointer... And because of the -moz-binding bug described at the beginning, we also need :

  <binding id="unwebchunkIcon">
        if  (document.body.mHovered == this)
 this.style.visibility = 'hidden';

So the mHovered field in the body is here only to manage the element-to-icon change while the mSlice field of the icon itself will hold the reference to the originating element. There's a last thing you need to have, that's the onFloaterClick() method, there's a trick you should know (thanks Neil !):

  onFloaterClick: function webchunks_onFloaterClick(event)
    var target = event.originalTarget;
    if(target.nodeType == Node.ELEMENT_NODE &&
       target.nodeName.toLowerCase() == "html:img" &&
       target.getAttribute("anonid") == "webchunkIcon")

Done. Again, that's a bit tricky and ugly for two reasons : the -moz-binding bug and the fact the icon cannot be a child of the originating element. You can probably make a bit simpler writing a single binding for the icon itself and playing with mouseover and mouseout event handlers but I'm not here yet myself :-)

Hoping that helps !