summaryrefslogtreecommitdiffstats
path: root/mailnews/base/content/newmailalert.js
blob: f54d165b1e0881106b78f343303454a5c2967e51 (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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/* 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/. */

Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource:///modules/iteratorUtils.jsm");

// Copied from nsILookAndFeel.h, see comments on eMetric_AlertNotificationOrigin
var NS_ALERT_HORIZONTAL = 1;
var NS_ALERT_LEFT = 2;
var NS_ALERT_TOP = 4;

var gNumNewMsgsToShowInAlert = 4; // the more messages we show in the alert, the larger it will be
var gOpenTime = 4000; // total time the alert should stay up once we are done animating.

var gAlertListener = null;
var gPendingPreviewFetchRequests = 0;
var gUserInitiated = false;
var gOrigin = 0; // Default value: alert from bottom right.

function prefillAlertInfo()
{
  const Ci = Components.interfaces;
  // unwrap all the args....
  // arguments[0] --> nsIArray of folders with new mail
  // arguments[1] --> the observer to call back with notifications about the alert
  // arguments[2] --> user initiated boolean. true if the user initiated opening the alert
  //                 (which means skip the fade effect and don't auto close the alert)
  // arguments[3] --> the alert origin returned by the look and feel
  var foldersWithNewMail = window.arguments[0];
  gAlertListener = window.arguments[1];
  gUserInitiated = window.arguments[2];
  gOrigin = window.arguments[3];

  // For now just grab the first folder which should be a root folder
  // for the account that has new mail. If we can't find a folder, just
  // return to avoid the exception and empty dialog in upper left-hand corner.
  if (!foldersWithNewMail || foldersWithNewMail.length < 1)
    return;
  let rootFolder = foldersWithNewMail.queryElementAt(0, Ci.nsIWeakReference)
                                     .QueryReferent(Ci.nsIMsgFolder);

  // Generate an account label string based on the root folder.
  var label = document.getElementById('alertTitle');
  var totalNumNewMessages = rootFolder.getNumNewMessages(true);
  var message = totalNumNewMessages == 1 ? "newMailNotification_message"
                                         : "newMailNotification_messages";
  label.value = document.getElementById('bundle_messenger')
                        .getFormattedString(message,
                                            [rootFolder.prettiestName,
                                             totalNumNewMessages]);

  // This is really the root folder and we have to walk through the list to
  // find the real folder that has new mail in it...:(
  let allFolders = rootFolder.descendants;
  var folderSummaryInfoEl = document.getElementById('folderSummaryInfo');
  folderSummaryInfoEl.mMaxMsgHdrsInPopup = gNumNewMsgsToShowInAlert;
  for (let folder in fixIterator(allFolders, Components.interfaces.nsIMsgFolder))
  {
    if (folder.hasNewMessages) {
      let notify =
        // Any folder which is an inbox or ...
        folder.getFlag(Ci.nsMsgFolderFlags.Inbox) ||
        // any non-special or non-virtual folder. In other words, we don't
        // notify for Drafts|Trash|SentMail|Templates|Junk|Archive|Queue or virtual.
        !(folder.flags & (Ci.nsMsgFolderFlags.SpecialUse | Ci.nsMsgFolderFlags.Virtual));

      if (notify) {
        var asyncFetch = {};
        folderSummaryInfoEl.parseFolder(folder, new urlListener(folder), asyncFetch);
        if (asyncFetch.value)
          gPendingPreviewFetchRequests++;
      }
    }
  }
}

function urlListener(aFolder)
{
  this.mFolder = aFolder;
}

urlListener.prototype =
{
  OnStartRunningUrl: function(aUrl)
  {
  },

  OnStopRunningUrl: function(aUrl, aExitCode)
  {
    var folderSummaryInfoEl = document.getElementById('folderSummaryInfo');
    folderSummaryInfoEl.parseFolder(this.mFolder, null, {});
    gPendingPreviewFetchRequests--;

    // when we are done running all of our urls for fetching the preview text,
    // start the alert.
    if (!gPendingPreviewFetchRequests)
      showAlert();
  }
}

function onAlertLoad()
{
  prefillAlertInfo();
  // read out our initial settings from prefs.
  try
  {
    gOpenTime = Services.prefs.getIntPref("alerts.totalOpenTime");
  } catch (ex) {}

  // bogus call to make sure the window is moved offscreen until we are ready for it.
  resizeAlert(true);

  // if we aren't waiting to fetch preview text, then go ahead and
  // start showing the alert.
  if (!gPendingPreviewFetchRequests)
    setTimeout(showAlert, 0); // let the JS thread unwind, to give layout
                              // a chance to recompute the styles and widths for our alert text.
}

// If the user initiated the alert, show it right away, otherwise start opening the alert with
// the fade effect.
function showAlert()
{
  if (!document.getElementById("folderSummaryInfo").hasMessages) {
    closeAlert(); // no mail, so don't bother showing the alert...
    return;
  }

  // resize the alert based on our current content
  resizeAlert(false);

  var alertContainer = document.getElementById("alertContainer");
  // Don't fade in if the user opened the alert or the pref is true.
  if (gUserInitiated ||
      Services.prefs.getBoolPref("alerts.disableSlidingEffect")) {
    alertContainer.setAttribute("noanimation", true);
    setTimeout(closeAlert, gOpenTime);
    return;
  }

  alertContainer.addEventListener("animationend", function hideAlert(event) {
    if (event.animationName == "fade-in") {
      alertContainer.removeEventListener("animationend", hideAlert, false);
      let remaining = Math.max(Math.round(gOpenTime - event.elapsedTime * 1000), 0);
      setTimeout(fadeOutAlert, remaining);
    }
  }, false);
  alertContainer.setAttribute("fade-in", true);
}

function resizeAlert(aMoveOffScreen)
{
  var alertTextBox = document.getElementById("alertTextBox");
  var alertImageBox = document.getElementById("alertImageBox");
  alertImageBox.style.minHeight = alertTextBox.scrollHeight + "px";

  sizeToContent();

  // leftover hack to get the window properly hidden when we first open it
  if (aMoveOffScreen)
    window.outerHeight = 1;

  // Determine position
  var x = gOrigin & NS_ALERT_LEFT ? screen.availLeft :
          screen.availLeft + screen.availWidth - window.outerWidth;
  var y = gOrigin & NS_ALERT_TOP ? screen.availTop :
          screen.availTop + screen.availHeight - window.outerHeight;

  // Offset the alert by 10 pixels from the edge of the screen
  y += gOrigin & NS_ALERT_TOP ? 10 : -10;
  x += gOrigin & NS_ALERT_LEFT ? 10 : -10;

  window.moveTo(x, y);
}

function fadeOutAlert()
{
  var alertContainer = document.getElementById("alertContainer");
  alertContainer.addEventListener("animationend", function fadeOut(event) {
    if (event.animationName == "fade-out") {
      alertContainer.removeEventListener("animationend", fadeOut, false);
      closeAlert();
    }
  }, false);
  alertContainer.setAttribute("fade-out", true);
}

function closeAlert()
{
  if (gAlertListener)
    gAlertListener.observe(null, "alertfinished", "");
  window.close();
}