zulip/static/js/typing_status.js

142 lines
4.3 KiB
JavaScript

var typing_status = (function () {
var exports = {};
// See docs/subsystems/typing-indicators.md for details on typing indicators.
// The following constants are tuned to work with
// TYPING_STARTED_EXPIRY_PERIOD, which is what the other
// users will use to time out our messages. (Or us,
// depending on your perspective.) See typing_events.js.
// How frequently 'still typing' notifications are sent
// to extend the expiry
var TYPING_STARTED_WAIT_PERIOD = 10000; // 10s
// How long after someone stops editing in the compose box
// do we send a 'stopped typing' notification
var TYPING_STOPPED_WAIT_PERIOD = 5000; // 5s
/*
Our parent should pass in a worker object with the following
callbacks:
notify_server_start
notify_server_stop
get_recipient
get_current_time
is_valid_conversation
See typing.js for the implementations of the above. (Our
node tests also act as workers and will stub those functions
appropriately.)
*/
exports.state = {};
exports.initialize_state = function () {
exports.state.current_recipient = undefined;
exports.state.next_send_start_time = undefined;
exports.state.idle_timer = undefined;
};
exports.initialize_state();
exports.stop_last_notification = function stop_last_notification(worker) {
if (exports.state.idle_timer) {
clearTimeout(exports.state.idle_timer);
}
worker.notify_server_stop(exports.state.current_recipient);
exports.initialize_state();
};
exports.start_or_extend_idle_timer = function start_or_extend_idle_timer(worker) {
function on_idle_timeout() {
// We don't do any real error checking here, because
// if we've been idle, we need to tell folks, and if
// our current recipient has changed, previous code will
// have stopped the timer.
exports.stop_last_notification(worker);
}
if (exports.state.idle_timer) {
clearTimeout(exports.state.idle_timer);
}
exports.state.idle_timer = setTimeout(
on_idle_timeout,
TYPING_STOPPED_WAIT_PERIOD
);
};
function set_next_start_time(current_time) {
exports.state.next_send_start_time = current_time + TYPING_STARTED_WAIT_PERIOD;
}
function actually_ping_server(worker, recipient, current_time) {
worker.notify_server_start(recipient);
set_next_start_time(current_time);
}
exports.maybe_ping_server = function maybe_ping_server(worker, recipient) {
var current_time = worker.get_current_time();
if (current_time > exports.state.next_send_start_time) {
actually_ping_server(worker, recipient, current_time);
}
};
exports.handle_text_input = function (worker) {
var new_recipient = worker.get_recipient();
var current_recipient = exports.state.current_recipient;
if (current_recipient) {
// We need to use _.isEqual for comparisons; === doesn't work
// on arrays.
if (_.isEqual(new_recipient, current_recipient)) {
// Nothing has really changed, except we may need
// to send a ping to the server.
exports.maybe_ping_server(worker, new_recipient);
// We can also extend out our idle time.
exports.start_or_extend_idle_timer(worker);
return;
}
// We apparently stopped talking to our old recipient,
// so we must stop the old notification. Don't return
// yet, because we may have a new recipient.
exports.stop_last_notification(worker);
}
if (!worker.is_valid_conversation(new_recipient)) {
// If we are not talking to somebody we care about,
// then there is no more action to take.
return;
}
// We just started talking to this recipient, so notify
// the server.
exports.state.current_recipient = new_recipient;
var current_time = worker.get_current_time();
actually_ping_server(worker, new_recipient, current_time);
exports.start_or_extend_idle_timer(worker);
};
exports.stop = function (worker) {
// We get this if somebody closes the compose box, but
// it doesn't necessarily mean we had typing indicators
// active before this.
if (exports.state.current_recipient) {
exports.stop_last_notification(worker);
}
};
return exports;
}());
if (typeof module !== 'undefined') {
module.exports = typing_status;
}
window.typing_status = typing_status;