2

Creating a XulRunner application for Windows I found that if binding B extends binding A. And B is being removed, then only destructor of B is called, not followed by a call of A's destructor.

Is there something wrong with my code, or this is a XulRunner bug (I haven't find matching bug in bugzilla)?

log after binding B is removed

Here is an example that I tested on XulRunner 23 and 35:

main.xul:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window id="main" title="My App" width="500" height="300" sizemode="normal"
        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
        xmlns:html="http://www.w3.org/1999/xhtml">
  <script><![CDATA[
    function print(aString) {
      document.getElementById("log_msg").value += aString + "\n";
    }
    function removeElementById(aId) {
      document.getElementById(aId).remove();
    };
    function callF(aId) {
      document.getElementById(aId).f();
    }
  ]]></script>
  <vbox flex="1">
    <label onclick="removeElementById('A')">remove A</label>
    <label onclick="removeElementById('B')">remove B</label>
    <label onclick="callF('A')">Call A.f()</label>
    <label onclick="callF('B')">Call B.f()</label>
    <!--<binding-a id="A" style="-moz-binding: url('binding.xml#binding-a')"/>-->
    <binding-b id="B" style="-moz-binding: url('binding.xml#binding-b')"/>
    <textbox id="log_msg" label="Text" placeholder="placeholder" multiline="true" rows="6"/>
  </vbox>
</window>

binding.xml:

<?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="binding-a">
    <content>
      <xul:label anonid="label" value="Binding A"/>
    </content>
    <implementation>
      <constructor><![CDATA[
        var label = document.getAnonymousElementByAttribute(this, "anonid", "label");
        label.value = label.value + " A.constructor";
        window.print("A.constructor");
      ]]></constructor>
      <destructor><![CDATA[
        window.print("A.destructor");
      ]]></destructor>
      <method name="f">
        <body><![CDATA[
          window.print("A.f");
        ]]></body>
      </method>
    </implementation>
  </binding>

  <binding id="binding-b" extends="#binding-a">
    <content>
      <xul:label anonid="label" value="Binding B"/>
    </content>
    <implementation>
      <constructor><![CDATA[
        window.print("B.constructor");
      ]]></constructor>
      <destructor><![CDATA[
        window.print("B.destructor");
      ]]></destructor>
    </implementation>
  </binding>
</bindings>
Paolo Forgia
  • 6,572
  • 8
  • 46
  • 58
Sergey Avdeev
  • 910
  • 1
  • 8
  • 16
  • 1
    This is a problem I and others have hit as well, these are the things that were discussed: https://ask.mozilla.org/question/297/apply-and-remove-xbl-binding-on-runtime/ | https://ask.mozilla.org/question/271/my-xbl-is-not-working-on-findbar/ | https://stackoverflow.com/questions/24403667/dynamic-way-to-unbind-dynamically-binded-xbl | and theres some more ill have to dig it up – Noitidart Apr 08 '15 at 03:50

1 Answers1

1

here is the solution for your problem:

bindings.xml:

<?xml version="1.0"?>
<bindings xmlns="http://www.mozilla.org/xbl"
     xmlns:xbl="http://www.mozilla.org/xbl" 
     xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <binding id="binding-a">
    <content>
      <xul:label anonid="label" value="Binding A"/>
    </content>
    <implementation>
      <constructor><![CDATA[
        var label = document.getAnonymousElementByAttribute(this, "anonid", "label");
        label.value = label.value + " A.constructor";
        window.print("A.constructor");
      ]]></constructor>
      <destructor><![CDATA[
        this.destruct();
      ]]></destructor>
      <method name="f">
        <body><![CDATA[
          window.print("A.f");
        ]]></body>
      </method>
      <method name="destruct">
        <body><![CDATA[
          window.print("A.destructor");
        ]]></body>
      </method>
    </implementation>
  </binding>

  <binding id="binding-b" extends="#binding-a">
    <content>
      <xul:label anonid="label" value="Binding B"/>
    </content>
    <implementation>
      <constructor><![CDATA[
        window.print("B.constructor");
      ]]></constructor>
      <destructor><![CDATA[
          this.destruct();
      ]]></destructor>
      <method name="destruct">
        <body><![CDATA[
        this.__proto__.__proto__.destruct.call(this);
          window.print("B.destructor");
        ]]></body>
      </method>
    </implementation>
  </binding>
</bindings> 

bindings.css:

@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");

binding-a { -moz-binding: url("bindings.xml#binding-a"); }
binding-b { -moz-binding: url("bindings.xml#binding-b"); }

main.xul:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="bindings.css" type="text/css"?>
<window id="main" title="My App" width="500" height="300" sizemode="normal"
        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
        xmlns:html="http://www.w3.org/1999/xhtml">
  <script><![CDATA[
    function print(aString) {
      document.getElementById("log_msg").value += aString + "\n";
    }
    function removeElementById(aId) {
      document.getElementById(aId).remove();
    };
    function callF(aId) {
      document.getElementById(aId).f();
    }
  ]]></script>
  <vbox flex="1">
    <label onclick="removeElementById('A')">remove A</label>
    <label onclick="removeElementById('B')">remove B</label>
    <label onclick="callF('A')">Call A.f()</label>
    <label onclick="callF('B')">Call B.f()</label>
    <binding-a id="A"/>
    <binding-b id="B"/>
    <textbox id="log_msg" label="Text" placeholder="placeholder" multiline="true" rows="6"/>
  </vbox>
</window>

I know that it is a hack in fact but it works.

Ondřej Doněk
  • 529
  • 1
  • 10
  • 17
  • I like `this.__proto__.__proto__.destruct.call(this)`. Could you confirm that this problem actually exists for you in your environment? In your workaround do I have to create `destruct` method? Can I call `` of `binding-a` directly? – Sergey Avdeev Apr 09 '15 at 19:03
  • 1
    I can confirm that `` in extended binding is not called automatically when the child binding is destroyed. This is just a work-around - a hack if you want. – Ondřej Doněk Apr 09 '15 at 19:09
  • 1
    The problem with destructors is old and it doesn't look that will be fixed ever - https://bugzilla.mozilla.org/show_bug.cgi?id=230086 – Ondřej Doněk Apr 09 '15 at 19:14
  • 1
    And one more note - in fact when the document is destroyed fully (e.g. document or window is closed) destructor of `binding-a` was called properly after destructor of `binding-b` but this doesn't work when you removing element by JavaScript. – Ondřej Doněk Apr 09 '15 at 19:18