mail/components/im/content/imconv.xml
author Richard Marti <richard.marti@gmail.com>
Mon, 21 Jan 2019 17:49:00 +0100
changeset 33963 fa0f40f25bae898175e89590f4c2d23770a49fb5
parent 33960 48b416ee9271b60a781429b96e671fe4e4ea93e0
child 34399 985a367b6423f28e297d4c55d0256e741e91d225
permissions -rw-r--r--
Bug 1521481 - Hide chat conversation number indicator when its value is "0" by copying the xbl:inherits to the surrounding box. r=florian a=jorgk

<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->

<!DOCTYPE bindings [
  <!ENTITY % chatDTD SYSTEM "chrome://messenger/locale/chat.dtd" >
  %chatDTD;
]>

<bindings id="convBindings"
          xmlns="http://www.mozilla.org/xbl"
          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns:xbl="http://www.mozilla.org/xbl"
          xmlns:html="http://www.w3.org/1999/xhtml">

  <binding id="conv" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
    <content>
      <xul:vbox class="box-line" xbl:inherits="selected"/>
      <xul:button anonid="closeConversationButton" class="closeConversationButton close-icon"
                  tooltiptext="&closeConversationButton.tooltip;"/>
      <xul:stack class="prplBuddyIcon" mousethrough="always">
        <xul:image class="protoIcon" xbl:inherits="src=iconPrpl,status"/>
        <xul:image class="statusIcon" xbl:inherits="status"/>
      </xul:stack>
      <xul:hbox flex="1" class="conv-hbox" mousethrough="always">
        <xul:label crop="end" flex="1" mousethrough="always"
                   anonid="displayname" class="convDisplayName blistDisplayName"
                   xbl:inherits="value=displayname,status"/>
        <xul:label anonid="unreadCount" class="convUnreadCount"
                   crop="end" mousethrough="never"
                   xbl:inherits="value=unreadCount"/>
        <xul:box class="convUnreadTargetedCount"
                 xbl:inherits="value=unreadTargetedCount">
          <xul:label anonid="unreadTargetedCount" class="convUnreadTargetedCountLabel"
                     crop="end" mousethrough="never"
                     xbl:inherits="value=unreadTargetedCount"/>
        </xul:box>
        <xul:spacer flex="1000000"/>
      </xul:hbox>
    </content>
    <implementation implements="nsIObserver">

     <constructor>
      <![CDATA[
        new MutationObserver(aMutations => {
          if (!this.convView || !this.convView.loaded)
            return;
          if (this.hasAttribute("selected"))
            this.convView.switchingToPanel();
          else
            this.convView.switchingAwayFromPanel();
        }).observe(this, {attributes: true, attributeFilter: ["selected"]});
      ]]>
     </constructor>

     <destructor>
      <![CDATA[
        if (this.conv) {
          this.conv.removeObserver(this);
          delete this.conv;
        }
      ]]>
     </destructor>

     <field name="convView">null</field>
     <method name="build">
      <parameter name="aConv"/>
      <body>
      <![CDATA[
        this.conv = aConv;
        this.conv.addObserver(this);
        this.update();
      ]]>
      </body>
     </method>

     <property name="displayName"
               onget="return this.conv.title;"/>

     <!-- for compatibility with the  imgroup sortComparator -->
     <property name="contact"
               onget="return this.conv;"/>

     <!-- nsIObserver implementation -->
     <method name="observe">
       <parameter name="aSubject"/>
       <parameter name="aTopic"/>
       <parameter name="aData"/>
       <body>
       <![CDATA[
         if (aTopic == "target-prpl-conversation-changed" ||
             aTopic == "unread-message-count-changed" ||
             aTopic == "update-conv-title" ||
             aTopic == "update-buddy-status" ||
             aTopic == "update-buddy-status" ||
             aTopic == "update-conv-chatleft" ||
             aTopic == "update-conv-chatjoining" ||
             aTopic == "chat-update-topic")
           this.update();
         if (aTopic == "update-conv-title")
           this.group.updateContactPosition(this.conv);
       ]]>
       </body>
     </method>

     <property name="selected">
       <getter><![CDATA[
           return gChatTab && gChatTab.tabNode.selected &&
                  this.getAttribute("selected") == "true";
         ]]></getter>
       <setter><![CDATA[
         if (val)
           this.setAttribute("selected", "true");
         else
           this.removeAttribute("selected");

         return val;
         ]]></setter>
     </property>

     <field name="directedUnreadCount">0</field>
     <method name="update">
      <body>
      <![CDATA[
        this.setAttribute("displayname", this.displayName);
        if (this.selected && document.hasFocus()) {
          if (this.convView && this.convView.loaded) {
            this.conv.markAsRead();
            this.directedUnreadCount = 0;
            chatHandler.updateTitle();
            chatHandler.updateChatButtonState();
          }
          this.setAttribute("unreadCount", "0");
          this.setAttribute("unreadTargetedCount", "0");
          this.removeAttribute("unread");
          this.removeAttribute("attention");
        } else {
          let unreadCount = this.conv.unreadIncomingMessageCount;
          let directedMessages = unreadCount;
          if (unreadCount) {
            this.setAttribute("unread", "true");
            if (this.conv.isChat) {
              directedMessages = this.conv.unreadTargetedMessageCount;
              if (directedMessages)
                this.setAttribute("attention", "true");
            }
            unreadCount -= directedMessages;
            if (directedMessages > this.directedUnreadCount)
              this.directedUnreadCount = directedMessages;
          }
          if (unreadCount)
            unreadCount = "(" + unreadCount + ")";
          this.setAttribute("unreadCount", unreadCount);
          if (Services.prefs.getBoolPref("messenger.options.getAttentionOnNewMessages") &&
              directedMessages > parseInt(this.getAttribute("unreadTargetedCount")))
            window.getAttention();
          this.setAttribute("unreadTargetedCount", directedMessages);
          chatHandler.updateTitle();
        }

        if (this.conv.isChat) {
          if (this.conv.joining)
            this.setAttribute("status", "joining");
          else if (!this.conv.account.connected || this.conv.left)
            this.setAttribute("status", "left");
          else
            this.removeAttribute("status");
        } else {
          let statusType = Ci.imIStatusInfo.STATUS_UNKNOWN;
          let buddy = this.conv.buddy;
          if (buddy && buddy.account.connected)
            statusType = buddy.statusType;
          if (!("Status" in window))
            ChromeUtils.import("resource:///modules/imStatusUtils.jsm");
          this.setAttribute("status", Status.toAttribute(statusType));
        }

        this.setAttribute("iconPrpl",
                          this.conv.account.protocol.iconBaseURI + "icon.png");
      ]]>
      </body>
     </method>

     <method name="destroy">
      <body>
      <![CDATA[
        if (this.conv)
          this.conv.removeObserver(this);
        if (this.convView) {
          this.convView.destroy();
          this.convView.remove();
        }

        // If the conversation we are destroying was selected, we should
        // select something else, but the 'select' event handler of
        // the listbox will choke while updating the Chat tab title if
        // there are conversation nodes associated with a conversation
        // that no longer exists from the chat core's point of view, so
        // we do the actual selection change only after this conversation
        // item is fully destroyed and removed from the list.
        let newSelectedItem;
        let list = this.parentNode;
        if (list.selectedItem == this)
          newSelectedItem = this.previousSibling;

        if (this.log) {
          this.hidden = true;
          delete this.log;
        } else {
          this.remove();
          delete this.conv;
        }
        if (newSelectedItem)
          list.selectedItem = newSelectedItem;
      ]]>
      </body>
     </method>

     <method name="closeConversation">
      <body>
       <![CDATA[
         if (this.conv)
           this.conv.close();
         else
           this.destroy();
       ]]>
      </body>
     </method>

     <method name="keyPress">
      <parameter name="aEvent"/>
      <body>
      <![CDATA[
        // If Enter or Return is pressed, focus the input box.
        if (aEvent.keyCode == aEvent.DOM_VK_RETURN) {
          this.convView.focus();
          return;
        }

        let isMac = "nsILocalFileMac" in Ci;
        let accelKeyPressed = isMac ? aEvent.metaKey : aEvent.ctrlKey;
        // If a character was typed or the accel+v copy shortcut was used,
        // focus the input box and resend the key event.
        if (aEvent.charCode != 0 && !aEvent.altKey &&
            (accelKeyPressed && aEvent.charCode == "v".charCodeAt(0) ||
             !aEvent.ctrlKey && !aEvent.metaKey)) {
          this.convView.focus();

          let clonedEvent = new KeyboardEvent("keypress", aEvent);
          this.convView.editor.inputField.dispatchEvent(clonedEvent);
          aEvent.preventDefault();
        }
      ]]>
      </body>
     </method>
    </implementation>
    <handlers>
     <handler event="mousedown" phase="capturing">
       <![CDATA[
         let anonid = event.originalTarget.getAttribute("anonid");
         if (anonid == "closeConversationButton") {
           this.closeConversation();
           event.stopPropagation();
           event.preventDefault();
         }
       ]]>
     </handler>
    </handlers>
  </binding>
</bindings>