1

I am applying a binding like this in a restartless add-on:

var css = '.findbar-container { -moz-binding:url("' + self.path.chrome + 'findbar.xml#matchword") }';
var cssEnc = encodeURIComponent(css);
var newURIParam = {
    aURL: 'data:text/css,' + cssEnc,
    aOriginCharset: null,
    aBaseURI: null
}
cssUri = Services.io.newURI(newURIParam.aURL, newURIParam.aOriginCharset, newURIParam.aBaseURI);
myServices.sss.loadAndRegisterSheet(cssUri, myServices.sss.USER_SHEET);

findbar.xml contents are:

<?xml version="1.0"?>
<bindings xmlns="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
    <binding id="matchword">
        <content>
            <children/>
            <xul:toolbarbutton anonid="matchwordbtn" accesskey="w" class="tabbable" label="Whole Word Only" tooltiptext="Match only whole words" oncommand="console.log('hi')" type="checkbox"/>
        </content>
    </binding>
</bindings>

This just adds a button to the FindBar labeled "Whole Word Only". But now to remove it, I am just unregistering the stylesheet with myServices.sss.unregisterSheet(cssUri, myServices.sss.USER_SHEET);, however this is not unbinding it.

An answer on ask.mozilla.org told me this is expected behavior, but offered no solution.

I was thinking maybe I should dynamically add the binding rather than via CSS, I didn't test this but it doesn't fit the 3 reasons for XBL updates:

  1. A bound element matches a style rule that specifies a different binding
  2. The element is removed from the bound document
  3. The element is destroyed (e.g., by closing the document)

The answer told me it's expected yet funky behavior.

nmaier
  • 32,336
  • 5
  • 63
  • 78
Noitidart
  • 35,443
  • 37
  • 154
  • 323

1 Answers1

1

Well, I just remembered that I have some working code that does (re)bind different XBL bindings, essentially.

It goes like this:

  • There is a base binding, or not (in your case the original binding of .findbar-container).
  • Then I have multiple classes that define different -moz-bindings.
  • These classes are set and removed at runtime.

Since that works for me, it should in theory work for you:

  • In your style, do not have a rule for the element itself, but for a class, e.g.

    .findbar-container.myaddonclass { moz-binding: ... }
    
  • In your code, on load add that new class, e.g.

    Array.forEach(
      document.querySelectorAll(".findbar-container"),
      e => e.classList.add("myaddonclass")
      );
    
  • In your code, on unload remove the class again:

    Array.forEach(
      document.querySelectorAll(".findbar-container"),
      e => e.classList.remove("myaddonclass")
      );
    

This should force a CSS-rule reevaluation, and bindings reevaluation with that and hence fits the "A bound element matches a style rule that specifies a different binding" rule.

Of course, this sucks when not all elements you want to rebind are already present on load of your add-on, but MutationObserver could help with that...

nmaier
  • 32,336
  • 5
  • 63
  • 78
  • 1
    PS: Here is some code I use. [CSS rules (those `richlistitem` ones)](https://github.com/downthemall/anticontainer/blob/ac5d4e5119dc72cbeb2fe53e744ba84c05f386d8/skin/prefpane.css) and [corresponding bindings](https://github.com/downthemall/anticontainer/blob/ac5d4e5119dc72cbeb2fe53e744ba84c05f386d8/content/bindings.xml). – nmaier Jun 25 '14 at 15:31
  • I was looking into this more, the reason I do `.findbar-container { moz-binding: ... }` is because findbar is seperate in all tabs now and it isnt initalized till the user does ctrl+f for first time in tab, so if i decide to add it with custom class, i have to listen and respond to initialize of findbar. so im looking for a method to trigger the xbl reflow, i tried setting dummy class names but that didnt trigger it, im trying to find a way right now. edit: oh i see you addressed that with MutationObserver, im trying to just iterate on shutdown to clear the binding from what has it attached – Noitidart Jan 07 '15 at 21:05