为什么在删除扩展绑定时不调用扩展绑定的析构函数?

Why destructor of an extended binding is not called when extending binding is removed?

为 Windows 创建 XulRunner 应用程序我发现如果绑定 B 扩展绑定 A。并且 B 被删除,然后只调用 B 的析构函数,而不是调用 A的析构函数。

我的代码有问题吗,或者这是一个 XulRunner 错误(我在 bugzilla 中没有找到匹配的错误)?

这是我在 XulRunner 23 和 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>

这是您的问题的解决方案:

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>

我知道这实际上是一个 hack,但它确实有效。