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',
|
|
|
|
idle: 'is not active'
|
|
|
|
};
|
|
|
|
|
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) {
|
|
|
|
if (message.type === 'private') {
|
|
|
|
if (message.reply_to.indexOf(',') > 0) {
|
2016-11-17 23:16:29 +01:00
|
|
|
var user_ids_string = people.emails_strings_to_user_ids_string(
|
|
|
|
message.reply_to);
|
|
|
|
|
|
|
|
if (!user_ids_string) {
|
|
|
|
blueslip.warn('Bad reply_to for huddle: ' + message.reply_to);
|
|
|
|
}
|
|
|
|
|
|
|
|
var old_timestamp = huddle_timestamps.get(user_ids_string);
|
2013-10-23 20:44:31 +02:00
|
|
|
|
|
|
|
if (!old_timestamp || (old_timestamp < message.timestamp)) {
|
2016-11-17 23:16:29 +01:00
|
|
|
huddle_timestamps.set(user_ids_string, message.timestamp);
|
2016-11-11 19:30:04 +01:00
|
|
|
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
|
|
|
});
|
|
|
|
|
2016-11-14 23:52:03 +01:00
|
|
|
var email_dict = people.filter_people_by_search_terms(persons, search_terms);
|
2016-11-17 21:43:12 +01:00
|
|
|
user_ids = _.map(_.keys(email_dict), function (email) {
|
|
|
|
return people.get_user_id(email);
|
|
|
|
});
|
|
|
|
return user_ids;
|
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 {
|
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],
|
2016-11-17 21:43:12 +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),
|
2016-01-19 21:03:56 +01:00
|
|
|
fraction_present: exports.huddle_fraction_present(huddle, exports.presence_info),
|
2013-10-18 00:56:49 +02:00
|
|
|
short_name: exports.short_huddle_name(huddle)
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
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) {
|
2016-06-08 05:54:07 +02:00
|
|
|
if (!util.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();
|
2013-03-13 20:02:57 +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) {
|
2016-06-08 05:54:07 +02:00
|
|
|
if (util.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;
|
|
|
|
}
|