2012-11-23 23:53:38 +01:00
|
|
|
var notifications = (function () {
|
|
|
|
|
|
|
|
var exports = {};
|
|
|
|
|
2012-11-26 23:57:31 +01:00
|
|
|
var notice_memory = {};
|
2013-09-16 18:22:52 +02:00
|
|
|
|
|
|
|
// When you start Zulip, window_has_focus should be true, but it might not be the
|
|
|
|
// case after a server-initiated reload.
|
|
|
|
var window_has_focus = document.hasFocus && document.hasFocus();
|
|
|
|
|
2013-01-08 16:54:44 +01:00
|
|
|
var asked_permission_already = false;
|
2013-01-09 23:49:54 +01:00
|
|
|
var names;
|
2013-05-03 21:36:38 +02:00
|
|
|
var supports_sound;
|
2012-11-23 23:53:38 +01:00
|
|
|
|
2013-06-28 20:51:28 +02:00
|
|
|
var unread_pms_favicon = '/static/images/favicon/favicon-pms.png';
|
|
|
|
var current_favicon;
|
|
|
|
var previous_favicon;
|
|
|
|
var flashing = false;
|
|
|
|
|
2012-11-26 23:57:31 +01:00
|
|
|
function browser_desktop_notifications_on () {
|
|
|
|
return (window.webkitNotifications &&
|
2013-01-21 21:50:33 +01:00
|
|
|
// Firefox on Ubuntu claims to do webkitNotifications but its notifications are terrible
|
|
|
|
$.browser.webkit &&
|
2012-11-26 23:57:31 +01:00
|
|
|
// 0 is PERMISSION_ALLOWED
|
2013-05-31 22:25:39 +02:00
|
|
|
window.webkitNotifications.checkPermission() === 0) ||
|
|
|
|
// window.bridge is the desktop client
|
|
|
|
(window.bridge !== undefined);
|
2012-11-26 23:57:31 +01:00
|
|
|
}
|
2012-11-23 23:53:38 +01:00
|
|
|
|
2013-08-29 22:58:00 +02:00
|
|
|
function cancel_notification_object (notification_object) {
|
|
|
|
// We must remove the .onclose so that it does not trigger on .cancel
|
|
|
|
notification_object.onclose = function () {};
|
|
|
|
notification_object.onclick = function () {};
|
|
|
|
notification_object.cancel();
|
|
|
|
}
|
|
|
|
|
2012-11-26 23:57:31 +01:00
|
|
|
exports.initialize = function () {
|
2012-11-23 23:53:38 +01:00
|
|
|
$(window).focus(function () {
|
|
|
|
window_has_focus = true;
|
2012-11-27 18:26:36 +01:00
|
|
|
|
2013-07-30 00:35:44 +02:00
|
|
|
_.each(notice_memory, function (notice_mem_entry) {
|
2013-08-29 22:58:00 +02:00
|
|
|
cancel_notification_object(notice_mem_entry.obj);
|
2012-11-27 18:26:36 +01:00
|
|
|
});
|
2013-08-29 22:58:00 +02:00
|
|
|
notice_memory = {};
|
2013-07-11 17:14:11 +02:00
|
|
|
|
|
|
|
// Update many places on the DOM to reflect unread
|
|
|
|
// counts.
|
|
|
|
process_visible_unread_messages();
|
|
|
|
|
2012-11-23 23:53:38 +01:00
|
|
|
}).blur(function () {
|
|
|
|
window_has_focus = false;
|
|
|
|
});
|
|
|
|
|
2013-06-27 22:15:00 +02:00
|
|
|
if ($.browser.mozilla === true && typeof Notification !== "undefined") {
|
2013-07-05 17:43:56 +02:00
|
|
|
Notification.requestPermission(function () {
|
2013-06-27 22:15:00 +02:00
|
|
|
asked_permission_already = true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-07-05 20:47:41 +02:00
|
|
|
if (window.bridge !== undefined) {
|
|
|
|
supports_sound = true;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-03 21:36:38 +02:00
|
|
|
var audio = $("<audio>");
|
2013-07-05 20:47:41 +02:00
|
|
|
if (audio[0].canPlayType === undefined) {
|
2013-05-03 21:36:38 +02:00
|
|
|
supports_sound = false;
|
|
|
|
} else {
|
|
|
|
supports_sound = true;
|
|
|
|
$("#notifications-area").append(audio);
|
|
|
|
if (audio[0].canPlayType('audio/ogg; codecs="vorbis"')) {
|
|
|
|
audio.append($("<source>").attr("type", "audio/ogg")
|
|
|
|
.attr("loop", "yes")
|
2013-10-31 19:04:31 +01:00
|
|
|
.attr("src", "/static/audio/zulip.ogg"));
|
2013-05-03 21:36:38 +02:00
|
|
|
} else {
|
|
|
|
audio.append($("<source>").attr("type", "audio/mpeg")
|
|
|
|
.attr("loop", "yes")
|
2013-10-31 19:04:31 +01:00
|
|
|
.attr("src", "/static/audio/zulip.mp3"));
|
2013-05-03 21:36:38 +02:00
|
|
|
}
|
|
|
|
}
|
2013-07-12 20:12:12 +02:00
|
|
|
|
|
|
|
if (window.webkitNotifications) {
|
|
|
|
$(document).click(function () {
|
|
|
|
if (!page_params.desktop_notifications_enabled || asked_permission_already) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (window.webkitNotifications.checkPermission() !== 0) { // 0 is PERMISSION_ALLOWED
|
|
|
|
window.webkitNotifications.requestPermission(function () {});
|
|
|
|
asked_permission_already = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2012-11-23 23:53:38 +01:00
|
|
|
};
|
|
|
|
|
2013-08-14 23:17:15 +02:00
|
|
|
// For web pages, the initial favicon is the same as the favicon we
|
|
|
|
// set for no unread messages and the initial page title is the same
|
|
|
|
// as the page title we set for no unread messages. However, for the
|
|
|
|
// OS X app, the dock icon does not get its badge updated on initial
|
|
|
|
// page load. If the badge icon was wrong right before a reload and
|
|
|
|
// we actually have no unread messages then we will never execute
|
|
|
|
// bridge.updateCount() until the unread count changes. Therefore,
|
|
|
|
// we ensure that bridge.updateCount is always run at least once to
|
|
|
|
// synchronize it with the page title. This can be done before the
|
|
|
|
// DOM is loaded.
|
|
|
|
if (window.bridge !== undefined) {
|
|
|
|
window.bridge.updateCount(0);
|
|
|
|
}
|
|
|
|
|
Clean up code for unread counts and notifications.
The core simplification here is that zephyr.js no longer has:
* the global home_unread_messages
* the function unread_in_current_view() [which used the global]
The logic that used to be in zephyr is now in its proper home
of unread.js, which has these changes:
* the structure returned from unread.get_counts() includes
a new member called unread_in_current_view
* there's a helper function unread.num_unread_current_messages()
Deprecating zephyr.unread_in_current_view() affected two callers:
* notifications.update_title_count()
* notifications_bar.update()
The above functions used to call back to zephyr to get counts, but
there was no nice way to enforce that they were getting counts
at the right time in the code flow, because they depended on
functions like process_visible_unread_messages() to orchestrate
updating internal unread counts before pushing out counts to the DOM.
Now both of those function take a parameter with the unread count,
and we then had to change all of their callers appropriately. This
went hand in hand with another goal, which is that we want all the
unread-counts logic to funnel though basically one place, which
is zephyr.update_unread_counts(). So now that function always
calls notifications_bar.update() [NEW] as well as calling into
the modules unread.js, stream_list.js, and notifications.js [OLD].
Adding the call to notifications_bar.update() in update_unread_counts()
made it so that some other places in the code no longer needed to call
notifications_bar.update(), so you'll see some lines of code
removed. There are also cases where notifications.update_title_count()
was called redundantly, since the callers were already reaching
update_unread_counts() via other calls.
Finally, in ui.resizehandler, you'll see a simple case where the call
to notifications_bar.update() is preceded by an explicit call
to unread.get_counts().
(imported from commit ce84b9c8076c1f9bb20a61209913f0cb0dae098c)
2013-06-05 21:04:06 +02:00
|
|
|
exports.update_title_count = function (new_message_count) {
|
2013-03-19 21:53:49 +01:00
|
|
|
// Update window title and favicon to reflect unread messages in current view
|
|
|
|
var n;
|
|
|
|
|
2013-05-06 22:35:10 +02:00
|
|
|
var new_title = (new_message_count ? ("(" + new_message_count + ") ") : "")
|
2013-10-17 17:58:47 +02:00
|
|
|
+ page_params.realm_name + " - Zulip";
|
2013-03-19 21:53:49 +01:00
|
|
|
|
2013-05-06 22:35:10 +02:00
|
|
|
if (document.title === new_title) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
document.title = new_title;
|
|
|
|
|
2013-03-19 21:53:49 +01:00
|
|
|
// IE doesn't support PNG favicons, *shrug*
|
|
|
|
if (! $.browser.msie) {
|
|
|
|
// Indicate the message count in the favicon
|
|
|
|
if (new_message_count) {
|
|
|
|
// Make sure we're working with a number, as a defensive programming
|
|
|
|
// measure. And we don't have images above 99, so display those as
|
|
|
|
// 'infinite'.
|
|
|
|
n = (+new_message_count);
|
2013-08-01 17:47:48 +02:00
|
|
|
if (n > 99) {
|
2013-03-19 21:53:49 +01:00
|
|
|
n = 'infinite';
|
2013-08-01 17:47:48 +02:00
|
|
|
}
|
2013-03-19 21:53:49 +01:00
|
|
|
|
2013-06-28 20:51:28 +02:00
|
|
|
current_favicon = previous_favicon = '/static/images/favicon/favicon-'+n+'.png';
|
2013-03-19 21:53:49 +01:00
|
|
|
} else {
|
2013-06-28 20:51:28 +02:00
|
|
|
current_favicon = previous_favicon = '/static/favicon.ico?v=2';
|
2013-03-19 21:53:49 +01:00
|
|
|
}
|
2013-06-28 20:51:28 +02:00
|
|
|
util.set_favicon(current_favicon);
|
2013-03-19 21:53:49 +01:00
|
|
|
}
|
2013-06-02 20:42:03 +02:00
|
|
|
|
|
|
|
if (window.bridge !== undefined) {
|
|
|
|
// We don't use 'n' because we want the exact count. The bridge handles
|
|
|
|
// which icon to show.
|
|
|
|
window.bridge.updateCount(new_message_count);
|
|
|
|
}
|
2013-03-19 21:53:49 +01:00
|
|
|
};
|
|
|
|
|
2013-06-28 20:51:28 +02:00
|
|
|
function flash_pms() {
|
|
|
|
// When you have unread PMs, toggle the favicon between the unread count and
|
|
|
|
// a special icon indicating that you have unread PMs.
|
|
|
|
if (unread.get_counts().private_message_count > 0) {
|
|
|
|
if (current_favicon === unread_pms_favicon) {
|
|
|
|
util.set_favicon(previous_favicon);
|
|
|
|
current_favicon = previous_favicon;
|
|
|
|
previous_favicon = unread_pms_favicon;
|
|
|
|
} else {
|
|
|
|
util.set_favicon(unread_pms_favicon);
|
|
|
|
previous_favicon = current_favicon;
|
|
|
|
current_favicon = unread_pms_favicon;
|
|
|
|
}
|
|
|
|
// Toggle every 2 seconds.
|
|
|
|
setTimeout(flash_pms, 2000);
|
|
|
|
} else {
|
|
|
|
flashing = false;
|
|
|
|
// You have no more unread PMs, so back to only showing the unread
|
|
|
|
// count.
|
|
|
|
util.set_favicon(current_favicon);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-19 00:00:40 +02:00
|
|
|
exports.update_pm_count = function (new_pm_count) {
|
|
|
|
if (window.bridge !== undefined && window.bridge.updatePMCount !== undefined) {
|
|
|
|
window.bridge.updatePMCount(new_pm_count);
|
|
|
|
}
|
2013-06-28 20:51:28 +02:00
|
|
|
if (!flashing) {
|
|
|
|
flashing = true;
|
|
|
|
flash_pms();
|
|
|
|
}
|
2013-06-19 00:00:40 +02:00
|
|
|
};
|
|
|
|
|
2013-03-04 23:44:07 +01:00
|
|
|
exports.window_has_focus = function () {
|
|
|
|
return window_has_focus;
|
|
|
|
};
|
|
|
|
|
2013-06-27 22:15:00 +02:00
|
|
|
function in_browser_notify(message, title, content) {
|
|
|
|
var notification_html = $(templates.render('notification', {gravatar_url: ui.small_avatar_url(message),
|
|
|
|
title: title,
|
|
|
|
content: content}));
|
|
|
|
$('.top-right').notify({
|
2013-10-09 22:42:15 +02:00
|
|
|
message: {html: notification_html},
|
|
|
|
fadeOut: {enabled: true, delay: 4000}
|
2013-06-27 22:15:00 +02:00
|
|
|
}).show();
|
|
|
|
}
|
|
|
|
|
2013-10-09 22:42:15 +02:00
|
|
|
exports.notify_above_composebox = function (title, content, link_class, link_msg_id, link_text) {
|
|
|
|
var notification_html = $(templates.render('compose-notification', {title: title,
|
|
|
|
content: content,
|
|
|
|
link_class: link_class,
|
|
|
|
link_msg_id: link_msg_id,
|
|
|
|
link_text: link_text}));
|
|
|
|
$('#compose-notifications').notify({
|
|
|
|
message: {html: notification_html},
|
|
|
|
fadeOut: {enabled: true, delay: 8000}
|
|
|
|
}).show();
|
|
|
|
};
|
|
|
|
|
2013-06-19 01:41:27 +02:00
|
|
|
function process_notification(notification) {
|
2013-07-22 22:21:34 +02:00
|
|
|
var i, notification_object, key, content, other_recipients;
|
2013-06-19 01:41:27 +02:00
|
|
|
var message = notification.message;
|
2012-11-23 23:53:38 +01:00
|
|
|
var title = message.sender_full_name;
|
|
|
|
var msg_count = 1;
|
|
|
|
|
2013-07-22 22:21:34 +02:00
|
|
|
// Convert the content to plain text, replacing emoji with their alt text
|
|
|
|
content = $('<div/>').html(message.content);
|
2013-07-23 00:25:25 +02:00
|
|
|
ui.replace_emoji_with_text(content);
|
2013-07-22 22:21:34 +02:00
|
|
|
content = content.text();
|
|
|
|
|
2013-01-09 23:49:54 +01:00
|
|
|
if (message.type === "private") {
|
|
|
|
key = message.display_reply_to;
|
|
|
|
other_recipients = message.display_reply_to;
|
|
|
|
// Remove the sender from the list of other recipients
|
|
|
|
other_recipients = other_recipients.replace(", " + message.sender_full_name, "");
|
|
|
|
other_recipients = other_recipients.replace(message.sender_full_name + ", ", "");
|
|
|
|
} else {
|
|
|
|
key = message.sender_full_name + " to " +
|
2013-04-18 17:13:43 +02:00
|
|
|
message.stream + " > " + message.subject;
|
2013-01-09 23:49:54 +01:00
|
|
|
}
|
2012-11-23 23:53:38 +01:00
|
|
|
|
|
|
|
if (content.length > 150) {
|
|
|
|
// Truncate content at a word boundary
|
|
|
|
for (i = 150; i > 0; i--) {
|
|
|
|
if (content[i] === ' ') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
content = content.substring(0, i);
|
|
|
|
content += " [...]";
|
|
|
|
}
|
|
|
|
|
2013-05-31 22:25:39 +02:00
|
|
|
if (window.bridge === undefined && notice_memory[key] !== undefined) {
|
2012-11-23 23:53:38 +01:00
|
|
|
msg_count = notice_memory[key].msg_count + 1;
|
|
|
|
title = msg_count + " messages from " + title;
|
|
|
|
notification_object = notice_memory[key].obj;
|
2013-08-29 22:58:00 +02:00
|
|
|
cancel_notification_object(notification_object);
|
2012-11-23 23:53:38 +01:00
|
|
|
}
|
|
|
|
|
2012-12-03 19:49:12 +01:00
|
|
|
if (message.type === "private" && message.display_recipient.length > 2) {
|
2012-11-23 23:53:38 +01:00
|
|
|
// If the message has too many recipients to list them all...
|
|
|
|
if (content.length + title.length + other_recipients.length > 230) {
|
|
|
|
// Then count how many people are in the conversation and summarize
|
|
|
|
// by saying the conversation is with "you and [number] other people"
|
|
|
|
other_recipients = other_recipients.replace(/[^,]/g, "").length +
|
|
|
|
" other people";
|
|
|
|
}
|
|
|
|
title += " (to you and " + other_recipients + ")";
|
|
|
|
}
|
2013-01-09 23:49:54 +01:00
|
|
|
if (message.type === "stream") {
|
2013-04-18 17:13:43 +02:00
|
|
|
title += " (to " + message.stream + " > " + message.subject + ")";
|
2013-01-09 23:49:54 +01:00
|
|
|
}
|
2012-11-23 23:53:38 +01:00
|
|
|
|
2013-06-27 22:15:00 +02:00
|
|
|
if (window.bridge === undefined && notification.webkit_notify === true) {
|
2013-06-13 23:48:23 +02:00
|
|
|
var icon_url = ui.small_avatar_url(message);
|
2013-05-31 22:25:39 +02:00
|
|
|
notice_memory[key] = {
|
|
|
|
obj: window.webkitNotifications.createNotification(
|
2013-06-13 23:48:23 +02:00
|
|
|
icon_url, title, content),
|
2013-08-29 22:58:00 +02:00
|
|
|
msg_count: msg_count,
|
|
|
|
message_id: message.id
|
2013-05-31 22:25:39 +02:00
|
|
|
};
|
|
|
|
notification_object = notice_memory[key].obj;
|
|
|
|
notification_object.onclick = function () {
|
|
|
|
notification_object.cancel();
|
|
|
|
window.focus();
|
|
|
|
};
|
|
|
|
notification_object.onclose = function () {
|
|
|
|
delete notice_memory[key];
|
|
|
|
};
|
|
|
|
notification_object.show();
|
2013-06-27 22:15:00 +02:00
|
|
|
} else if (notification.webkit_notify === false && typeof Notification !== "undefined" && $.browser.mozilla === true) {
|
|
|
|
Notification.requestPermission(function (perm) {
|
|
|
|
if (perm === 'granted') {
|
|
|
|
Notification(title, {
|
|
|
|
body: content,
|
|
|
|
iconUrl: ui.small_avatar_url(message)
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
in_browser_notify(message, title, content);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else if (notification.webkit_notify === false) {
|
|
|
|
in_browser_notify(message, title, content);
|
2013-05-31 22:25:39 +02:00
|
|
|
} else {
|
|
|
|
// Shunt the message along to the desktop client
|
2013-06-14 00:25:02 +02:00
|
|
|
window.bridge.desktopNotification(title, content);
|
2013-05-31 22:25:39 +02:00
|
|
|
}
|
2012-11-23 23:53:38 +01:00
|
|
|
}
|
|
|
|
|
2013-08-29 22:58:00 +02:00
|
|
|
exports.close_notification = function (message) {
|
|
|
|
_.each(Object.keys(notice_memory), function (key) {
|
|
|
|
if (notice_memory[key].message_id === message.id) {
|
|
|
|
cancel_notification_object(notice_memory[key].obj);
|
|
|
|
delete notice_memory[key];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2013-03-12 22:36:13 +01:00
|
|
|
exports.speaking_at_me = function (message) {
|
2013-05-31 16:15:27 +02:00
|
|
|
if (message === undefined) {
|
2013-01-10 04:47:11 +01:00
|
|
|
return false;
|
2013-01-10 17:24:39 +01:00
|
|
|
}
|
2013-05-31 16:15:27 +02:00
|
|
|
|
|
|
|
return message.mentioned;
|
2013-03-12 22:36:13 +01:00
|
|
|
};
|
2013-01-09 23:49:54 +01:00
|
|
|
|
2013-05-03 21:49:01 +02:00
|
|
|
function message_is_notifiable(message) {
|
2013-10-18 19:28:29 +02:00
|
|
|
// Based purely on message contents, can we notify the user about
|
|
|
|
// the message?
|
|
|
|
|
|
|
|
// First, does anything disqualify it from being notifiable?
|
|
|
|
if (message.sent_by_me) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-10-18 19:47:16 +02:00
|
|
|
if ((message.type === "stream") &&
|
|
|
|
!stream_data.in_home_view(message.stream)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ((message.type === "stream") &&
|
|
|
|
muting.is_topic_muted(message.stream, message.subject)) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-10-18 19:28:29 +02:00
|
|
|
|
|
|
|
// Then, do any properties make it notifiable?
|
|
|
|
if (message.type === "private") {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (exports.speaking_at_me(message)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if ((message.type === "stream") &&
|
|
|
|
subs.receives_notifications(message.stream)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (alert_words.notifies(message)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nope.
|
|
|
|
return false;
|
2013-05-03 21:49:01 +02:00
|
|
|
}
|
|
|
|
|
2012-11-23 23:53:38 +01:00
|
|
|
exports.received_messages = function (messages) {
|
2013-07-30 00:35:44 +02:00
|
|
|
_.each(messages, function (message) {
|
2013-08-01 17:47:48 +02:00
|
|
|
if (!message_is_notifiable(message)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!unread.message_unread(message)) {
|
|
|
|
return;
|
|
|
|
}
|
2013-07-02 20:33:00 +02:00
|
|
|
|
2013-06-14 16:46:37 +02:00
|
|
|
if (page_params.desktop_notifications_enabled &&
|
|
|
|
browser_desktop_notifications_on()) {
|
2013-06-27 22:15:00 +02:00
|
|
|
process_notification({message: message, webkit_notify: true});
|
2013-08-01 17:47:48 +02:00
|
|
|
} else {
|
2013-06-27 22:15:00 +02:00
|
|
|
process_notification({message: message, webkit_notify: false});
|
2013-06-14 16:46:37 +02:00
|
|
|
}
|
|
|
|
if (page_params.sounds_enabled && supports_sound) {
|
|
|
|
if (window.bridge !== undefined) {
|
|
|
|
window.bridge.bell();
|
|
|
|
} else {
|
|
|
|
$("#notifications-area").find("audio")[0].play();
|
2012-11-26 23:57:31 +01:00
|
|
|
}
|
2012-11-23 23:53:38 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2013-10-09 22:42:15 +02:00
|
|
|
exports.possibly_notify_new_messages_outside_viewport = function (messages) {
|
2013-11-04 23:30:09 +01:00
|
|
|
if (!feature_flags.notify_on_send_not_in_view) {
|
2013-11-01 17:33:58 +01:00
|
|
|
return;
|
|
|
|
}
|
2013-10-09 22:42:15 +02:00
|
|
|
_.each(messages, function (message) {
|
|
|
|
if (message.sender_email !== page_params.email) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// queue up offscreen because of narrowed, or (secondarily) offscreen
|
|
|
|
// because it doesn't fit in the currently visible viewport
|
|
|
|
var msg_text = $(message.content).text();
|
|
|
|
var note;
|
|
|
|
var link_class;
|
|
|
|
var link_msg_id = message.id;
|
|
|
|
var link_text;
|
|
|
|
|
|
|
|
var row = current_msg_list.get_row(message.id);
|
|
|
|
if (row.length === 0) {
|
|
|
|
// offscreen because it is outside narrow
|
|
|
|
// we can only look for these on non-search (can_apply_locally) messages
|
|
|
|
// see also: exports.notify_messages_outside_current_search
|
|
|
|
note = "is outside the current narrow.";
|
|
|
|
link_class = "compose_notification_narrow_by_subject";
|
|
|
|
link_text = "narrow to that conversation";
|
|
|
|
}
|
|
|
|
else if (viewport.is_below_visible_bottom(row.offset().top + row.height()) && !narrow.narrowed_by_reply()){
|
|
|
|
// offscreen because it's too far down.
|
|
|
|
// offer scroll to message link.
|
|
|
|
note = "is further down.";
|
|
|
|
if (!narrow.active()) {
|
|
|
|
// in the home view, let's offer to take them to it.
|
|
|
|
link_class = "compose_notification_narrow_by_time_travel";
|
|
|
|
link_text = "show in context";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// return with _.each is like continue for normal for loops.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
exports.notify_above_composebox(msg_text, note, link_class, link_msg_id, link_text);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
// for callback when we have to check with the server if a message should be in
|
|
|
|
// the current_msg_list (!can_apply_locally; a.k.a. "a search").
|
|
|
|
exports.notify_messages_outside_current_search = function (messages) {
|
2013-11-04 23:30:09 +01:00
|
|
|
if (!feature_flags.notify_on_send_not_in_view) {
|
2013-11-01 17:33:58 +01:00
|
|
|
return;
|
|
|
|
}
|
2013-10-09 22:42:15 +02:00
|
|
|
_.each(messages, function (message) {
|
|
|
|
if (message.sender_email !== page_params.email) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
exports.notify_above_composebox($(message.content).text(),
|
|
|
|
"is outside the current search.",
|
|
|
|
"compose_notification_narrow_by_subject",
|
|
|
|
message.id,
|
|
|
|
"narrow to it");
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.clear_compose_notifications = function () {
|
|
|
|
$("#compose-notifications").children().remove();
|
|
|
|
};
|
|
|
|
|
2013-06-14 00:25:02 +02:00
|
|
|
$(function () {
|
|
|
|
// Shim for Cocoa WebScript exporting top-level JS
|
|
|
|
// objects instead of window.foo objects
|
|
|
|
if (typeof(bridge) !== 'undefined' && window.bridge === undefined) {
|
|
|
|
window.bridge = bridge;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2013-10-09 22:42:15 +02:00
|
|
|
exports.register_click_handlers = function () {
|
|
|
|
$('body').on('click', '.compose_notification_narrow_by_subject', function (e) {
|
|
|
|
var msgid = $(e.currentTarget).data('msgid');
|
|
|
|
narrow.by_subject(msgid, {trigger: 'compose_notification'});
|
|
|
|
e.stopPropagation();
|
|
|
|
e.preventDefault();
|
|
|
|
});
|
|
|
|
$('body').on('click', '.compose_notification_narrow_by_time_travel', function (e) {
|
|
|
|
var msgid = $(e.currentTarget).data('msgid');
|
|
|
|
narrow.by_time_travel(msgid, {trigger: 'compose_notification'});
|
|
|
|
scroll_to_selected();
|
|
|
|
e.stopPropagation();
|
|
|
|
e.preventDefault();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2012-11-23 23:53:38 +01:00
|
|
|
return exports;
|
|
|
|
|
|
|
|
}());
|