summaryrefslogtreecommitdiffstats
path: root/comm/mail/base/content/widgets/tabmail-tab.js
blob: 7de115149b91e19eccdfc9963f8af04b88d80979 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/* 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/. */

"use strict";

/* global MozElements, MozXULElement */

// Wrap in a block to prevent leaking to window scope.
{
  /**
   * The MozTabmailTab widget behaves as a tab in the messenger window.
   * It is used to navigate between different views. It displays information
   * about the view: i.e. name and icon.
   *
   * @augments {MozElements.MozTab}
   */
  class MozTabmailTab extends MozElements.MozTab {
    static get inheritedAttributes() {
      return {
        ".tab-background": "pinned,selected,titlechanged",
        ".tab-line": "selected=visuallyselected",
        ".tab-content": "pinned,selected,titlechanged,title=label",
        ".tab-throbber": "fadein,pinned,busy,progress,selected",
        ".tab-icon-image": "fadein,pinned,selected",
        ".tab-label-container": "pinned,selected=visuallyselected",
        ".tab-text": "text=label,accesskey,fadein,pinned,selected",
        ".tab-close-button": "fadein,pinned,selected=visuallyselected",
      };
    }

    connectedCallback() {
      if (this.delayConnectedCallback() || this.hasChildNodes()) {
        return;
      }

      this.setAttribute("is", "tabmail-tab");
      this.appendChild(
        MozXULElement.parseXULToFragment(
          `
          <stack class="tab-stack" flex="1">
            <vbox class="tab-background">
              <hbox class="tab-line"></hbox>
            </vbox>
            <html:div class="tab-content">
              <hbox class="tab-throbber" role="presentation"></hbox>
              <html:img class="tab-icon-image" alt="" role="presentation" />
              <hbox class="tab-label-container"
                    onoverflow="this.setAttribute('textoverflow', 'true');"
                    onunderflow="this.removeAttribute('textoverflow');"
                    flex="1">
                <label class="tab-text tab-label" role="presentation"></label>
              </hbox>
              <!-- We make the button non-focusable, otherwise each close
                 - button creates a new tab stop. See bug 1754097 -->
              <html:button class="plain-button tab-close-button"
                           tabindex="-1"
                           title="&closeTab.label;">
                <!-- Button title should provide the accessible context. -->
                <html:img class="tab-close-icon" alt=""
                          src="chrome://global/skin/icons/close.svg" />
              </html:button>
            </html:div>
          </stack>
          `,
          ["chrome://messenger/locale/tabmail.dtd"]
        )
      );

      this.addEventListener(
        "dragstart",
        event => {
          document.dragTab = this;
        },
        true
      );

      this.addEventListener(
        "dragover",
        event => {
          document.dragTab = null;
        },
        true
      );

      let closeButton = this.querySelector(".tab-close-button");

      // Prevent switching to the tab before closing it by stopping the
      // mousedown event.
      closeButton.addEventListener("mousedown", event => {
        if (event.button != 0) {
          return;
        }
        event.stopPropagation();
      });

      closeButton.addEventListener("click", () =>
        document.getElementById("tabmail").removeTabByNode(this)
      );

      // Middle mouse button click on the tab also closes it.
      this.addEventListener("click", event => {
        if (event.button != 1) {
          return;
        }
        document.getElementById("tabmail").removeTabByNode(this);
      });

      this.setAttribute("context", "tabContextMenu");

      this.mCorrespondingMenuitem = null;

      this.initializeAttributeInheritance();
    }

    get linkedBrowser() {
      let tabmail = document.getElementById("tabmail");
      let tab = tabmail._getTabContextForTabbyThing(this, false)[1];
      return tabmail.getBrowserForTab(tab);
    }

    get mode() {
      let tabmail = document.getElementById("tabmail");
      let tab = tabmail._getTabContextForTabbyThing(this, false)[1];
      return tab.mode;
    }

    /**
     * Set the displayed icon for the tab.
     *
     * If a fallback source if given, it will be used instead if the given icon
     * source is missing or loads with an error.
     *
     * If both sources are null, then the icon will become invisible.
     *
     * @param {string|null} iconSrc - The icon source to display in the tab, or
     *   null to just use the fallback source.
     * @param {?string} [fallbackSrc] - The fallback source to display if the
     *   iconSrc is missing or broken.
     */
    setIcon(iconSrc, fallbackSrc) {
      let icon = this.querySelector(".tab-icon-image");
      if (!fallbackSrc) {
        if (iconSrc) {
          icon.setAttribute("src", iconSrc);
        } else {
          icon.removeAttribute("src");
        }
        return;
      }
      if (!iconSrc) {
        icon.setAttribute("src", fallbackSrc);
        return;
      }
      if (iconSrc == icon.getAttribute("src")) {
        return;
      }

      // Set the tab image, and use the fallback if an error occurs.
      // Set up a one time listener for either error or load.
      let listener = event => {
        icon.removeEventListener("error", listener);
        icon.removeEventListener("load", listener);
        if (event.type == "error") {
          icon.setAttribute("src", fallbackSrc);
        }
      };
      icon.addEventListener("error", listener);
      icon.addEventListener("load", listener);
      icon.setAttribute("src", iconSrc);
    }
  }

  MozXULElement.implementCustomInterface(MozTabmailTab, [
    Ci.nsIDOMXULSelectControlItemElement,
  ]);

  customElements.define("tabmail-tab", MozTabmailTab, { extends: "tab" });
}