2013-02-07 19:57:45 +01:00
|
|
|
var activity = (function () {
|
2013-02-12 20:40:28 +01:00
|
|
|
var exports = {};
|
2013-02-07 19:57:45 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Helpers for detecting user activity and managing user idle states
|
|
|
|
*/
|
|
|
|
|
2013-08-20 20:57:26 +02:00
|
|
|
/* Broadcast "idle" to server after 5 minutes of local inactivity */
|
|
|
|
var DEFAULT_IDLE_TIMEOUT_MS = 5 * 60 * 1000;
|
2013-03-05 17:11:55 +01:00
|
|
|
/* Time between keep-alive pings */
|
2013-08-21 23:40:12 +02:00
|
|
|
var ACTIVE_PING_INTERVAL_MS = 50 * 1000;
|
2013-02-12 20:40:28 +01:00
|
|
|
|
2014-03-13 19:34:56 +01:00
|
|
|
/* Mark users as offline after 140 seconds since their last checkin,
|
2016-11-27 06:56:06 +01:00
|
|
|
* Keep in sync with zerver/tornado/event_queue.py:receiver_is_idle
|
2014-03-13 19:34:56 +01:00
|
|
|
*/
|
2013-08-21 23:40:12 +02:00
|
|
|
var OFFLINE_THRESHOLD_SECS = 140;
|
2013-02-07 19:57:45 +01:00
|
|
|
|
2014-02-27 01:46:17 +01:00
|
|
|
// Testing
|
|
|
|
exports._OFFLINE_THRESHOLD_SECS = OFFLINE_THRESHOLD_SECS;
|
|
|
|
|
2014-02-28 16:51:36 +01:00
|
|
|
var MOBILE_DEVICES = ["Android", "ZulipiOS", "ios"];
|
2014-02-27 01:46:17 +01:00
|
|
|
|
|
|
|
function is_mobile(device) {
|
|
|
|
return MOBILE_DEVICES.indexOf(device) !== -1;
|
|
|
|
}
|
2013-10-23 19:02:18 +02:00
|
|
|
|
|
|
|
var presence_descriptions = {
|
|
|
|
active: 'is active',
|
2017-01-12 00:17:43 +01:00
|
|
|
idle: 'is not active',
|
2013-10-23 19:02:18 +02:00
|
|
|
};
|
|
|
|
|
2016-04-03 08:01:10 +02:00
|
|
|
/* Keep in sync with views.py:update_active_status_backend() */
|
2013-08-20 21:18:56 +02:00
|
|
|
exports.ACTIVE = "active";
|
|
|
|
exports.IDLE = "idle";
|
2013-02-07 19:57:45 +01:00
|
|
|
|
2013-09-16 18:22:52 +02:00
|
|
|
// When you start Zulip, has_focus should be true, but it might not be the
|
|
|
|
// case after a server-initiated reload.
|
|
|
|
exports.has_focus = document.hasFocus && document.hasFocus();
|
2013-02-07 19:57:45 +01:00
|
|
|
|
2013-09-06 21:52:12 +02:00
|
|
|
// We initialize this to true, to count new page loads, but set it to
|
|
|
|
// false in the onload function in reload.js if this was a
|
|
|
|
// server-initiated-reload to avoid counting a server-initiated reload
|
|
|
|
// as user activity.
|
|
|
|
exports.new_user_input = true;
|
|
|
|
|
|
|
|
$("html").on("mousemove", function () {
|
|
|
|
exports.new_user_input = true;
|
|
|
|
});
|
|
|
|
|
2016-01-19 21:03:56 +01:00
|
|
|
exports.presence_info = {};
|
2013-04-03 22:00:02 +02:00
|
|
|
|
2013-10-23 20:44:31 +02:00
|
|
|
var huddle_timestamps = new Dict();
|
|
|
|
|
2016-11-11 20:48:13 +01:00
|
|
|
function update_count_in_dom(count_span, value_span, count) {
|
|
|
|
if (count === 0) {
|
|
|
|
count_span.hide();
|
|
|
|
if (count_span.parent().hasClass("user_sidebar_entry")) {
|
|
|
|
count_span.parent(".user_sidebar_entry").removeClass("user-with-count");
|
|
|
|
} else if (count_span.parent().hasClass("group-pms-sidebar-entry")) {
|
|
|
|
count_span.parent(".group-pms-sidebar-entry").removeClass("group-with-count");
|
|
|
|
}
|
|
|
|
value_span.text('');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
count_span.show();
|
|
|
|
|
|
|
|
if (count_span.parent().hasClass("user_sidebar_entry")) {
|
|
|
|
count_span.parent(".user_sidebar_entry").addClass("user-with-count");
|
|
|
|
} else if (count_span.parent().hasClass("group-pms-sidebar-entry")) {
|
|
|
|
count_span.parent(".group-pms-sidebar-entry").addClass("group-with-count");
|
|
|
|
}
|
|
|
|
value_span.text(count);
|
|
|
|
}
|
|
|
|
|
2016-11-17 23:16:29 +01:00
|
|
|
function get_filter_li(user_ids_string) {
|
2016-11-11 20:48:13 +01:00
|
|
|
if (name.indexOf(",") < 0) {
|
2016-11-17 23:16:29 +01:00
|
|
|
return $("li.user_sidebar_entry[data-user-id='" + user_ids_string + "']");
|
2016-11-11 20:48:13 +01:00
|
|
|
}
|
2016-12-02 21:34:35 +01:00
|
|
|
return $("li.group-pms-sidebar-entry[data-user-ids='" + user_ids_string + "']");
|
2016-11-11 20:48:13 +01:00
|
|
|
}
|
|
|
|
|
2016-11-17 23:16:29 +01:00
|
|
|
function set_count(user_ids_string, count) {
|
|
|
|
var count_span = get_filter_li(user_ids_string).find('.count');
|
2016-11-11 20:48:13 +01:00
|
|
|
var value_span = count_span.find('.value');
|
|
|
|
update_count_in_dom(count_span, value_span, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
exports.update_dom_with_unread_counts = function (counts) {
|
|
|
|
// counts is just a data object that gets calculated elsewhere
|
|
|
|
// Our job is to update some DOM elements.
|
|
|
|
|
2016-11-16 00:09:09 +01:00
|
|
|
counts.pm_count.each(function (count, user_ids_string) {
|
|
|
|
// TODO: just use user_ids_string in our markup
|
2016-11-17 23:16:29 +01:00
|
|
|
set_count(user_ids_string, count);
|
2016-11-11 20:48:13 +01:00
|
|
|
});
|
|
|
|
};
|
2014-02-27 01:46:17 +01:00
|
|
|
|
2013-10-23 20:44:31 +02:00
|
|
|
exports.process_loaded_messages = function (messages) {
|
2016-11-11 19:30:04 +01:00
|
|
|
var need_resize = false;
|
|
|
|
|
2013-10-23 20:44:31 +02:00
|
|
|
_.each(messages, function (message) {
|
2017-02-05 00:22:16 +01:00
|
|
|
var huddle_string = people.huddle_string(message);
|
2016-11-17 23:16:29 +01:00
|
|
|
|
2017-02-05 00:22:16 +01:00
|
|
|
if (huddle_string) {
|
|
|
|
var old_timestamp = huddle_timestamps.get(huddle_string);
|
2016-11-17 23:16:29 +01:00
|
|
|
|
2017-02-05 00:22:16 +01:00
|
|
|
if (!old_timestamp || (old_timestamp < message.timestamp)) {
|
|
|
|
huddle_timestamps.set(huddle_string, message.timestamp);
|
|
|
|
need_resize = true;
|
2013-10-23 20:44:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2016-11-11 18:00:09 +01:00
|
|
|
|
|
|
|
exports.update_huddles();
|
2016-11-11 19:30:04 +01:00
|
|
|
|
|
|
|
if (need_resize) {
|
|
|
|
resize.resize_page_components(); // big hammer
|
|
|
|
}
|
2013-10-23 20:44:31 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
exports.get_huddles = function () {
|
|
|
|
var huddles = huddle_timestamps.keys();
|
|
|
|
huddles = _.sortBy(huddles, function (huddle) {
|
|
|
|
return huddle_timestamps.get(huddle);
|
|
|
|
});
|
|
|
|
return huddles.reverse();
|
|
|
|
};
|
|
|
|
|
2013-10-23 22:22:34 +02:00
|
|
|
exports.full_huddle_name = function (huddle) {
|
2016-11-17 23:16:29 +01:00
|
|
|
var user_ids = huddle.split(',');
|
2013-10-23 22:22:34 +02:00
|
|
|
|
2016-11-17 23:16:29 +01:00
|
|
|
var names = _.map(user_ids, function (user_id) {
|
|
|
|
var person = people.get_person_from_user_id(user_id);
|
|
|
|
return person.full_name;
|
2013-10-23 22:22:34 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
return names.join(', ');
|
|
|
|
};
|
|
|
|
|
2013-11-04 22:59:03 +01:00
|
|
|
exports.short_huddle_name = function (huddle) {
|
2016-11-17 23:16:29 +01:00
|
|
|
var user_ids = huddle.split(',');
|
2013-11-04 22:59:03 +01:00
|
|
|
|
2013-12-05 22:20:20 +01:00
|
|
|
var num_to_show = 3;
|
2016-11-23 17:25:43 +01:00
|
|
|
var names = _.map(user_ids, function (user_id) {
|
2016-11-17 23:16:29 +01:00
|
|
|
var person = people.get_person_from_user_id(user_id);
|
|
|
|
return person.full_name;
|
2013-11-04 22:59:03 +01:00
|
|
|
});
|
2016-11-23 17:25:43 +01:00
|
|
|
|
|
|
|
names = _.sortBy(names, function (name) { return name.toLowerCase(); });
|
|
|
|
names = names.slice(0, num_to_show);
|
2016-11-17 23:16:29 +01:00
|
|
|
var others = user_ids.length - num_to_show;
|
2013-11-04 22:59:03 +01:00
|
|
|
|
|
|
|
if (others === 1) {
|
|
|
|
names.push("+ 1 other");
|
|
|
|
} else if (others >= 2) {
|
|
|
|
names.push("+ " + others + " others");
|
|
|
|
}
|
|
|
|
|
|
|
|
return names.join(', ');
|
|
|
|
};
|
|
|
|
|
2013-11-04 21:56:56 +01:00
|
|
|
exports.huddle_fraction_present = function (huddle, presence_info) {
|
2016-11-17 23:16:29 +01:00
|
|
|
var user_ids = huddle.split(',');
|
2013-11-04 21:56:56 +01:00
|
|
|
|
|
|
|
var num_present = 0;
|
2016-11-17 23:16:29 +01:00
|
|
|
_.each(user_ids, function (user_id) {
|
2016-11-17 21:43:12 +01:00
|
|
|
if (presence_info[user_id]) {
|
|
|
|
var status = presence_info[user_id].status;
|
2014-02-14 21:05:51 +01:00
|
|
|
if (status && (status !== 'offline')) {
|
2016-11-30 19:05:04 +01:00
|
|
|
num_present += 1;
|
2014-02-14 21:05:51 +01:00
|
|
|
}
|
2013-11-04 21:56:56 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-11-17 23:16:29 +01:00
|
|
|
var ratio = num_present / user_ids.length;
|
2013-11-04 21:56:56 +01:00
|
|
|
|
|
|
|
return ratio.toFixed(2);
|
|
|
|
};
|
|
|
|
|
2016-11-17 21:43:12 +01:00
|
|
|
function sort_users(user_ids, presence_info) {
|
2013-02-07 19:57:45 +01:00
|
|
|
// TODO sort by unread count first, once we support that
|
2016-11-17 21:43:12 +01:00
|
|
|
user_ids.sort(function (a, b) {
|
2014-02-14 21:05:51 +01:00
|
|
|
if (presence_info[a].status === 'active' && presence_info[b].status !== 'active') {
|
2013-02-12 20:40:28 +01:00
|
|
|
return -1;
|
2014-02-14 21:05:51 +01:00
|
|
|
} else if (presence_info[b].status === 'active' && presence_info[a].status !== 'active') {
|
2013-02-12 20:40:28 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-02-14 21:05:51 +01:00
|
|
|
if (presence_info[a].status === 'idle' && presence_info[b].status !== 'idle') {
|
2013-02-07 19:57:45 +01:00
|
|
|
return -1;
|
2014-02-14 21:05:51 +01:00
|
|
|
} else if (presence_info[b].status === 'idle' && presence_info[a].status !== 'idle') {
|
2013-02-07 19:57:45 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort equivalent PM names alphabetically
|
2013-02-15 21:01:49 +01:00
|
|
|
var full_name_a = a;
|
|
|
|
var full_name_b = b;
|
2016-11-17 21:43:12 +01:00
|
|
|
if (people.get_person_from_user_id(a)) {
|
|
|
|
full_name_a = people.get_person_from_user_id(a).full_name;
|
2013-02-15 21:01:49 +01:00
|
|
|
}
|
2016-11-17 21:43:12 +01:00
|
|
|
if (people.get_person_from_user_id(b)) {
|
|
|
|
full_name_b = people.get_person_from_user_id(b).full_name;
|
2013-02-15 21:01:49 +01:00
|
|
|
}
|
2013-05-03 19:16:50 +02:00
|
|
|
return util.strcmp(full_name_a, full_name_b);
|
2013-02-07 19:57:45 +01:00
|
|
|
});
|
|
|
|
|
2016-11-17 21:43:12 +01:00
|
|
|
return user_ids;
|
2013-02-07 19:57:45 +01:00
|
|
|
}
|
|
|
|
|
2013-08-09 14:42:49 +02:00
|
|
|
// for testing:
|
|
|
|
exports._sort_users = sort_users;
|
|
|
|
|
2013-02-07 19:57:45 +01:00
|
|
|
function focus_lost() {
|
2013-08-20 21:18:56 +02:00
|
|
|
if (!exports.has_focus) {
|
2013-02-07 19:57:45 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-08-20 21:18:56 +02:00
|
|
|
exports.has_focus = false;
|
2013-02-07 19:57:45 +01:00
|
|
|
}
|
|
|
|
|
2016-11-17 21:43:12 +01:00
|
|
|
function filter_user_ids(user_ids) {
|
2014-02-28 16:19:26 +01:00
|
|
|
var user_list = $(".user-list-filter");
|
|
|
|
if (user_list.length === 0) {
|
|
|
|
// We may have received an activity ping response after
|
|
|
|
// initiating a reload, in which case the user list may no
|
2016-01-19 21:03:56 +01:00
|
|
|
// longer be available.
|
|
|
|
// Return user list: useful for testing user list performance fix
|
2016-11-17 21:43:12 +01:00
|
|
|
return user_ids;
|
2014-02-28 16:19:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
var search_term = user_list.expectOne().val().trim();
|
2014-01-13 19:34:24 +01:00
|
|
|
if (search_term === '') {
|
2016-11-17 21:43:12 +01:00
|
|
|
return user_ids;
|
2014-01-13 19:34:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
var search_terms = search_term.toLowerCase().split(",");
|
|
|
|
search_terms = _.map(search_terms, function (s) {
|
|
|
|
return s.trim();
|
|
|
|
});
|
|
|
|
|
2016-11-17 21:43:12 +01:00
|
|
|
var persons = _.map(user_ids, function (user_id) {
|
|
|
|
return people.get_person_from_user_id(user_id);
|
2014-01-13 19:34:24 +01:00
|
|
|
});
|
|
|
|
|
2017-01-26 13:00:27 +01:00
|
|
|
var user_id_dict = people.filter_people_by_search_terms(persons, search_terms);
|
|
|
|
return user_id_dict.keys();
|
2014-01-13 19:34:24 +01:00
|
|
|
}
|
|
|
|
|
2016-01-19 21:03:56 +01:00
|
|
|
function filter_and_sort(users) {
|
2016-11-17 21:43:12 +01:00
|
|
|
var user_ids = Object.keys(users);
|
|
|
|
user_ids = filter_user_ids(user_ids);
|
|
|
|
user_ids = sort_users(user_ids, exports.presence_info);
|
|
|
|
return user_ids;
|
2016-01-19 21:03:56 +01:00
|
|
|
}
|
2016-11-14 23:52:03 +01:00
|
|
|
|
2016-01-19 21:03:56 +01:00
|
|
|
exports._filter_and_sort = filter_and_sort;
|
|
|
|
|
2016-03-20 07:03:00 +01:00
|
|
|
exports.update_users = function (user_list) {
|
2016-07-27 02:09:10 +02:00
|
|
|
if (page_params.presence_disabled) {
|
|
|
|
return;
|
2016-01-19 21:03:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
var users = exports.presence_info;
|
|
|
|
var all_users;
|
|
|
|
if (user_list !== undefined) {
|
|
|
|
all_users = filter_and_sort(users);
|
|
|
|
users = user_list;
|
|
|
|
}
|
|
|
|
users = filter_and_sort(users);
|
2013-10-23 19:12:40 +02:00
|
|
|
|
2016-11-18 17:02:06 +01:00
|
|
|
function get_num_unread(user_id) {
|
2014-01-31 18:06:38 +01:00
|
|
|
if (unread.suppress_unread_counts) {
|
2013-12-16 19:53:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2016-11-18 17:02:06 +01:00
|
|
|
return unread.num_unread_for_person(user_id);
|
2013-12-16 19:53:21 +01:00
|
|
|
}
|
|
|
|
|
2014-01-14 16:43:08 +01:00
|
|
|
// Note that we do not include ourselves in the user list any more.
|
|
|
|
// If you want to figure out how to get details for "me", then revert
|
|
|
|
// the commit that added this comment.
|
2013-10-23 19:02:18 +02:00
|
|
|
|
2016-11-17 21:43:12 +01:00
|
|
|
function info_for(user_id) {
|
|
|
|
var presence = exports.presence_info[user_id].status;
|
|
|
|
var person = people.get_person_from_user_id(user_id);
|
2013-10-23 19:02:18 +02:00
|
|
|
return {
|
Make nicer slugs for "pm-with" narrows.
The slugs for PM-with narrows now have user ids in them, so they
are more resilient to email changes, and they have less escaping
characters and are generally prettier.
Examples:
narrow/pm-with/3-cordelia
narrow/pm-with/3,5-group
The part of the URL that is actionable is the comma-delimited
list of one or more userids.
When we decode the slugs, we only use the part before the dash; the
stuff after the dash is just for humans. If we don't see a number
before the dash, we fall back to the old decoding (which should only
matter during a transition period where folks may have old links).
For group PMS, we always say "group" after the dash. For single PMs,
we use the person's email userid, since it's usually fairly concise
and not noisy for a URL. We may tinker with this later.
Basically, the heart of this change is these two new methods:
people.emails_to_slug
people.slug_to_emails
And then we unify the encode codepath as follows:
narrow.pm_with_uri ->
hashchange.operators_to_hash ->
hashchange.encode_operand ->
people.emails_to_slug
The decode path didn't really require much modication in this commit,
other than to have hashchange.decode_operand call people.slug_to_emails
for the pm-with case.
2017-01-06 02:00:03 +01:00
|
|
|
href: narrow.pm_with_uri(person.email),
|
2016-11-17 21:43:12 +01:00
|
|
|
name: person.full_name,
|
2016-11-17 23:16:29 +01:00
|
|
|
user_id: user_id,
|
2016-11-18 17:02:06 +01:00
|
|
|
num_unread: get_num_unread(user_id),
|
2013-10-23 19:02:18 +02:00
|
|
|
type: presence,
|
2014-02-27 01:46:17 +01:00
|
|
|
type_desc: presence_descriptions[presence],
|
2017-01-12 00:17:43 +01:00
|
|
|
mobile: exports.presence_info[user_id].mobile,
|
2013-10-23 19:02:18 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2014-01-14 16:46:43 +01:00
|
|
|
var user_info = _.map(users, info_for);
|
2016-01-19 21:03:56 +01:00
|
|
|
if (user_list !== undefined) {
|
|
|
|
// Render right panel partially
|
2016-12-02 14:06:06 +01:00
|
|
|
_.each(user_info, function (user) {
|
2016-11-17 23:16:29 +01:00
|
|
|
var user_index = all_users.indexOf(user.user_id);
|
|
|
|
$('#user_presences').find('[data-user-id="' + user.user_id + '"]').remove();
|
2016-03-20 07:35:32 +01:00
|
|
|
$('#user_presences li').eq(user_index).before(templates.render('user_presence_row', user));
|
2016-01-19 21:03:56 +01:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
$('#user_presences').html(templates.render('user_presence_rows', {users: user_info}));
|
|
|
|
}
|
2013-10-23 19:02:18 +02:00
|
|
|
|
|
|
|
// Update user fading, if necessary.
|
|
|
|
compose_fade.update_faded_users();
|
2016-01-19 21:03:56 +01:00
|
|
|
|
|
|
|
// Return updated users: useful for testing user performance fix
|
|
|
|
return user_info;
|
2016-03-20 07:03:00 +01:00
|
|
|
};
|
2014-01-13 19:34:24 +01:00
|
|
|
|
|
|
|
function actually_update_users_for_search() {
|
2016-03-20 07:03:00 +01:00
|
|
|
exports.update_users();
|
2014-03-13 19:03:31 +01:00
|
|
|
resize.resize_page_components();
|
2014-01-13 19:34:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
var update_users_for_search = _.throttle(actually_update_users_for_search, 50);
|
|
|
|
|
2016-12-05 07:02:18 +01:00
|
|
|
function show_huddles() {
|
2017-01-04 19:34:55 +01:00
|
|
|
$('#group-pm-list').addClass("show");
|
2016-11-11 19:30:04 +01:00
|
|
|
}
|
|
|
|
|
2016-12-05 07:02:18 +01:00
|
|
|
function hide_huddles() {
|
2017-01-04 19:34:55 +01:00
|
|
|
$('#group-pm-list').removeClass("show");
|
2016-11-11 19:30:04 +01:00
|
|
|
}
|
|
|
|
|
2013-10-18 00:56:49 +02:00
|
|
|
exports.update_huddles = function () {
|
2016-07-27 02:09:10 +02:00
|
|
|
if (page_params.presence_disabled) {
|
|
|
|
return;
|
2013-11-28 22:13:01 +01:00
|
|
|
}
|
|
|
|
|
2013-10-18 00:56:49 +02:00
|
|
|
var huddles = exports.get_huddles().slice(0, 10);
|
|
|
|
|
2013-12-03 16:44:42 +01:00
|
|
|
if (huddles.length === 0) {
|
2016-11-11 19:30:04 +01:00
|
|
|
hide_huddles();
|
2013-10-18 00:56:49 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var group_pms = _.map(huddles, function (huddle) {
|
|
|
|
return {
|
2016-11-17 23:16:29 +01:00
|
|
|
user_ids_string: huddle,
|
2013-10-18 00:56:49 +02:00
|
|
|
name: exports.full_huddle_name(huddle),
|
2017-01-06 15:01:14 +01:00
|
|
|
href: narrow.huddle_with_uri(huddle),
|
2016-01-19 21:03:56 +01:00
|
|
|
fraction_present: exports.huddle_fraction_present(huddle, exports.presence_info),
|
2017-01-12 00:17:43 +01:00
|
|
|
short_name: exports.short_huddle_name(huddle),
|
2013-10-18 00:56:49 +02:00
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
var html = templates.render('group_pms', {group_pms: group_pms});
|
|
|
|
$('#group-pms').expectOne().html(html);
|
2013-11-08 00:53:12 +01:00
|
|
|
|
2016-11-17 23:16:29 +01:00
|
|
|
_.each(huddles, function (user_ids_string) {
|
2016-11-18 17:02:06 +01:00
|
|
|
var count = unread.num_unread_for_person(user_ids_string);
|
2016-11-17 23:16:29 +01:00
|
|
|
set_count(user_ids_string, count);
|
2013-11-08 00:53:12 +01:00
|
|
|
});
|
|
|
|
|
2016-11-11 19:30:04 +01:00
|
|
|
show_huddles();
|
2013-10-18 00:56:49 +02:00
|
|
|
};
|
|
|
|
|
2013-05-06 17:14:59 +02:00
|
|
|
function status_from_timestamp(baseline_time, presence) {
|
2013-08-20 20:57:26 +02:00
|
|
|
var status = 'offline';
|
2014-02-27 01:46:17 +01:00
|
|
|
var mobileAvailable = false;
|
|
|
|
var nonmobileAvailable = false;
|
|
|
|
_.each(presence, function (device_presence, device) {
|
|
|
|
var age = baseline_time - device_presence.timestamp;
|
|
|
|
if (is_mobile(device)) {
|
|
|
|
mobileAvailable = device_presence.pushable || mobileAvailable;
|
|
|
|
}
|
|
|
|
if (age < OFFLINE_THRESHOLD_SECS) {
|
|
|
|
switch (device_presence.status) {
|
|
|
|
case 'active':
|
|
|
|
if (is_mobile(device)) {
|
|
|
|
mobileAvailable = true;
|
|
|
|
} else {
|
|
|
|
nonmobileAvailable = true;
|
|
|
|
}
|
|
|
|
status = device_presence.status;
|
|
|
|
break;
|
|
|
|
case 'idle':
|
|
|
|
if (status !== 'active') {
|
|
|
|
status = device_presence.status;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'offline':
|
|
|
|
if (status !== 'active' && status !== 'idle') {
|
|
|
|
status = device_presence.status;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2016-12-03 03:08:47 +01:00
|
|
|
blueslip.error('Unexpected status', {presence_object: device_presence, device: device}, undefined);
|
2014-02-27 01:46:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return {status: status, mobile: !nonmobileAvailable && mobileAvailable };
|
2013-04-05 00:13:03 +02:00
|
|
|
}
|
|
|
|
|
2014-02-27 01:46:17 +01:00
|
|
|
// For testing
|
|
|
|
exports._status_from_timestamp = status_from_timestamp;
|
|
|
|
|
2013-02-07 19:57:45 +01:00
|
|
|
function focus_ping() {
|
2014-01-07 23:41:55 +01:00
|
|
|
channel.post({
|
2016-04-03 07:58:06 +02:00
|
|
|
url: '/json/users/me/presence',
|
2014-01-07 23:41:55 +01:00
|
|
|
data: {status: (exports.has_focus) ? exports.ACTIVE : exports.IDLE,
|
|
|
|
new_user_input: exports.new_user_input},
|
|
|
|
idempotent: true,
|
|
|
|
success: function (data) {
|
2016-01-19 21:03:56 +01:00
|
|
|
exports.presence_info = {};
|
2014-01-07 23:41:55 +01:00
|
|
|
|
|
|
|
// Update Zephyr mirror activity warning
|
|
|
|
if (data.zephyr_mirror_active === false) {
|
|
|
|
$('#zephyr-mirror-error').show();
|
|
|
|
} else {
|
|
|
|
$('#zephyr-mirror-error').hide();
|
|
|
|
}
|
2013-06-12 19:58:25 +02:00
|
|
|
|
2014-01-07 23:41:55 +01:00
|
|
|
exports.new_user_input = false;
|
2013-02-07 19:57:45 +01:00
|
|
|
|
2014-01-07 23:41:55 +01:00
|
|
|
// Ping returns the active peer list
|
|
|
|
_.each(data.presences, function (presence, this_email) {
|
2017-01-19 20:18:03 +01:00
|
|
|
if (!people.is_current_user(this_email)) {
|
2016-11-17 21:43:12 +01:00
|
|
|
var user_id = people.get_user_id(this_email);
|
|
|
|
if (user_id) {
|
|
|
|
var status = status_from_timestamp(data.server_timestamp,
|
|
|
|
presence);
|
|
|
|
exports.presence_info[user_id] = status;
|
|
|
|
}
|
2014-01-07 23:41:55 +01:00
|
|
|
}
|
|
|
|
});
|
2016-03-20 07:03:00 +01:00
|
|
|
exports.update_users();
|
2014-01-07 23:41:55 +01:00
|
|
|
exports.update_huddles();
|
2017-01-12 00:17:43 +01:00
|
|
|
},
|
2013-02-07 19:57:45 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function focus_gained() {
|
2013-08-20 21:18:56 +02:00
|
|
|
if (!exports.has_focus) {
|
|
|
|
exports.has_focus = true;
|
2013-02-07 19:57:45 +01:00
|
|
|
|
|
|
|
focus_ping();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
exports.initialize = function () {
|
|
|
|
$(window).focus(focus_gained);
|
2013-02-12 20:40:28 +01:00
|
|
|
$(window).idle({idle: DEFAULT_IDLE_TIMEOUT_MS,
|
2013-02-07 19:57:45 +01:00
|
|
|
onIdle: focus_lost,
|
|
|
|
onActive: focus_gained,
|
|
|
|
keepTracking: true});
|
|
|
|
|
2013-08-20 20:57:26 +02:00
|
|
|
setInterval(focus_ping, ACTIVE_PING_INTERVAL_MS);
|
2013-04-05 00:13:03 +02:00
|
|
|
|
|
|
|
focus_ping();
|
2016-11-05 18:58:08 +01:00
|
|
|
|
|
|
|
activity.set_user_statuses(page_params.initial_presences,
|
|
|
|
page_params.initial_servertime);
|
2013-04-03 22:00:02 +02:00
|
|
|
};
|
|
|
|
|
2013-07-11 21:51:26 +02:00
|
|
|
// Set user statuses. `users` should be an object with user emails as keys
|
|
|
|
// and presence information (see `status_from_timestamp`) as values.
|
|
|
|
//
|
|
|
|
// The object does not need to include every user, only the ones
|
|
|
|
// whose presence you wish to update.
|
|
|
|
//
|
|
|
|
// This rerenders the user sidebar at the end, which can be slow if done too
|
|
|
|
// often, so try to avoid calling this repeatedly.
|
|
|
|
exports.set_user_statuses = function (users, server_time) {
|
2016-01-19 21:03:56 +01:00
|
|
|
var updated_users = {};
|
|
|
|
var status;
|
2013-07-30 00:35:44 +02:00
|
|
|
_.each(users, function (presence, email) {
|
2017-01-19 20:18:03 +01:00
|
|
|
if (people.is_current_user(email)) {
|
2013-07-11 21:51:26 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-01-19 21:03:56 +01:00
|
|
|
status = status_from_timestamp(server_time, presence);
|
2016-11-17 21:43:12 +01:00
|
|
|
var user_id = people.get_user_id(email);
|
|
|
|
if (user_id) {
|
|
|
|
exports.presence_info[user_id] = status;
|
|
|
|
updated_users[user_id] = status;
|
|
|
|
} else {
|
|
|
|
blueslip.warn('unknown email: ' + email);
|
|
|
|
}
|
2013-07-11 21:51:26 +02:00
|
|
|
});
|
2013-02-07 19:57:45 +01:00
|
|
|
|
2016-03-20 07:03:00 +01:00
|
|
|
exports.update_users(updated_users);
|
2013-10-18 00:56:49 +02:00
|
|
|
exports.update_huddles();
|
2013-02-07 19:57:45 +01:00
|
|
|
};
|
|
|
|
|
2017-01-04 23:54:59 +01:00
|
|
|
exports.redraw = function () {
|
|
|
|
exports.update_users();
|
|
|
|
exports.update_huddles();
|
|
|
|
};
|
|
|
|
|
2014-01-14 17:36:52 +01:00
|
|
|
exports.searching = function () {
|
|
|
|
return $('.user-list-filter').expectOne().is(':focus');
|
|
|
|
};
|
|
|
|
|
2014-02-14 22:36:20 +01:00
|
|
|
exports.escape_search = function () {
|
|
|
|
var filter = $('.user-list-filter').expectOne();
|
|
|
|
if (filter.val() === '') {
|
|
|
|
filter.blur();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
filter.val('');
|
2014-01-14 17:36:52 +01:00
|
|
|
update_users_for_search();
|
|
|
|
};
|
2014-01-13 19:34:24 +01:00
|
|
|
|
2014-02-14 22:49:26 +01:00
|
|
|
exports.initiate_search = function () {
|
|
|
|
var filter = $('.user-list-filter').expectOne();
|
|
|
|
filter.focus();
|
|
|
|
};
|
|
|
|
|
2014-01-14 17:57:34 +01:00
|
|
|
exports.blur_search = function () {
|
|
|
|
$('.user-list-filter').blur();
|
|
|
|
};
|
|
|
|
|
2016-12-05 07:02:18 +01:00
|
|
|
function maybe_select_person(e) {
|
2014-02-13 23:08:41 +01:00
|
|
|
if (e.keyCode === 13) {
|
|
|
|
// Enter key was pressed
|
|
|
|
|
|
|
|
// Prevent a newline from being entered into the soon-to-be-opened composebox
|
|
|
|
e.preventDefault();
|
|
|
|
|
2016-11-17 23:16:29 +01:00
|
|
|
var topPerson = $('#user_presences li.user_sidebar_entry').first().attr('data-user-id');
|
2016-12-09 20:42:28 +01:00
|
|
|
var user_list = $(".user-list-filter");
|
|
|
|
var search_term = user_list.expectOne().val().trim();
|
|
|
|
if ((topPerson !== undefined) && (search_term !== '')) {
|
2014-02-13 23:08:41 +01:00
|
|
|
// undefined if there are no results
|
2016-11-17 23:16:29 +01:00
|
|
|
var email = people.get_person_from_user_id(topPerson).email;
|
2014-02-13 23:08:41 +01:00
|
|
|
compose.start('private',
|
2016-12-03 03:08:47 +01:00
|
|
|
{trigger: 'sidebar enter key', private_message_recipient: email});
|
2014-02-13 23:08:41 +01:00
|
|
|
}
|
2016-04-29 23:48:51 +02:00
|
|
|
// Clear the user filter
|
|
|
|
exports.escape_search();
|
2014-02-13 23:08:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-05 07:02:18 +01:00
|
|
|
function focus_user_filter(e) {
|
2014-03-04 17:03:30 +01:00
|
|
|
e.stopPropagation();
|
|
|
|
}
|
|
|
|
|
2014-01-13 19:34:24 +01:00
|
|
|
$(function () {
|
2014-02-13 23:08:41 +01:00
|
|
|
$(".user-list-filter").expectOne()
|
2014-03-04 17:03:30 +01:00
|
|
|
.on('click', focus_user_filter)
|
2014-02-13 23:08:41 +01:00
|
|
|
.on('input', update_users_for_search)
|
|
|
|
.on('keydown', maybe_select_person);
|
2014-01-13 19:34:24 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
|
2013-02-07 19:57:45 +01:00
|
|
|
return exports;
|
|
|
|
|
|
|
|
}());
|
2013-08-09 14:42:49 +02:00
|
|
|
if (typeof module !== 'undefined') {
|
|
|
|
module.exports = activity;
|
|
|
|
}
|