2019-10-04 23:08:11 +02:00
|
|
|
const typing_status = require("../shared/js/typing_status");
|
2019-10-12 04:48:15 +02:00
|
|
|
|
2016-10-12 20:57:59 +02:00
|
|
|
var typing = (function () {
|
|
|
|
var exports = {};
|
|
|
|
|
2017-03-22 15:11:41 +01:00
|
|
|
// This module handles the outbound side of typing indicators.
|
|
|
|
// We detect changes in the compose box and notify the server
|
|
|
|
// when we are typing. For the inbound side see typing_events.js.
|
2017-09-25 20:33:29 +02:00
|
|
|
//
|
2017-11-08 17:55:36 +01:00
|
|
|
// See docs/subsystems/typing-indicators.md for details on typing indicators.
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2019-06-06 21:54:55 +02:00
|
|
|
function send_typing_notification_ajax(user_ids_array, operation) {
|
2016-10-12 20:57:59 +02:00
|
|
|
channel.post({
|
|
|
|
url: '/json/typing',
|
|
|
|
data: {
|
2019-06-06 21:54:55 +02:00
|
|
|
to: JSON.stringify(user_ids_array),
|
2016-10-12 20:57:59 +02:00
|
|
|
op: operation,
|
|
|
|
},
|
|
|
|
success: function () {},
|
|
|
|
error: function (xhr) {
|
|
|
|
blueslip.warn("Failed to send typing event: " + xhr.responseText);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-06-06 21:54:55 +02:00
|
|
|
function get_user_ids_array() {
|
2018-08-25 17:22:48 +02:00
|
|
|
var user_ids_string = compose_pm_pill.get_user_ids_string();
|
|
|
|
if (user_ids_string === "") {
|
2019-10-22 02:52:01 +02:00
|
|
|
return null;
|
2017-03-22 00:41:09 +01:00
|
|
|
}
|
2019-06-06 21:54:55 +02:00
|
|
|
|
|
|
|
return people.user_ids_string_to_ids_array(user_ids_string);
|
2017-03-22 00:41:09 +01:00
|
|
|
}
|
2016-10-12 20:57:59 +02:00
|
|
|
|
typing_status: Combine two parameters into one, with a maybe-type.
The main motivation for this change is to simplify this interface
and make it easier to reason about.
The case where it affects the behavior is when
is_valid_conversation() returns false, while current_recipient
and get_recipient() agree on some truthy value.
This means the message-content textarea is empty -- in fact the
user just cleared it, because we got here from an input event on
it -- but the compose box is still open to some PM thread that we
have a typing notification still outstanding for.
The old behavior is that in this situation we would ignore the
fact that the content was empty, and go ahead and prolong the
typing notification, by updating our timer and possibly sending a
"still typing" notice.
This contrasts with the behavior (both old and new) in the case
where the content is empty and we *don't* already have an
outstanding typing notification, or we have one to some other
thread. In that case, we cancel any existing notification and
don't start a new one, exactly as if `stop` were called
(e.g. because the user closed the compose box.)
The new behavior is that we always treat clearing the input as
"stopped typing": not only in those cases where we already did,
but also in the case where we still have the same recipients.
(Which seems like probably the common case.)
That seems like the preferable behavior; indeed it's hard to see
the point of the "compose_empty" logic if restricted to the other
cases. It also makes the interface simpler.
Those two properties don't seem like a coincidence, either: the
complicated interface made it difficult to unpack exactly what
logic we actually had, which made it easy for surprising wrinkles
to hang out indefinitely.
2019-10-21 23:37:22 +02:00
|
|
|
function is_valid_conversation() {
|
2017-03-22 00:41:09 +01:00
|
|
|
var compose_empty = !compose_state.has_message_content();
|
|
|
|
if (compose_empty) {
|
|
|
|
return false;
|
2016-10-12 20:57:59 +02:00
|
|
|
}
|
2017-03-22 00:41:09 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
function get_current_time() {
|
2019-10-05 01:44:22 +02:00
|
|
|
return new Date().getTime();
|
2016-10-12 20:57:59 +02:00
|
|
|
}
|
|
|
|
|
2019-10-04 23:57:34 +02:00
|
|
|
function notify_server_start(user_ids_array) {
|
|
|
|
send_typing_notification_ajax(user_ids_array, "start");
|
2017-03-22 00:41:09 +01:00
|
|
|
}
|
|
|
|
|
2019-10-04 23:57:34 +02:00
|
|
|
function notify_server_stop(user_ids_array) {
|
|
|
|
send_typing_notification_ajax(user_ids_array, "stop");
|
2017-03-22 00:41:09 +01:00
|
|
|
}
|
|
|
|
|
2019-06-07 03:17:35 +02:00
|
|
|
exports.get_recipient = get_user_ids_array;
|
2018-03-16 12:39:46 +01:00
|
|
|
exports.initialize = function () {
|
|
|
|
var worker = {
|
|
|
|
get_current_time: get_current_time,
|
|
|
|
notify_server_start: notify_server_start,
|
|
|
|
notify_server_stop: notify_server_stop,
|
|
|
|
};
|
|
|
|
|
|
|
|
$(document).on('input', '#compose-textarea', function () {
|
|
|
|
// If our previous state was no typing notification, send a
|
|
|
|
// start-typing notice immediately.
|
typing_status: Combine two parameters into one, with a maybe-type.
The main motivation for this change is to simplify this interface
and make it easier to reason about.
The case where it affects the behavior is when
is_valid_conversation() returns false, while current_recipient
and get_recipient() agree on some truthy value.
This means the message-content textarea is empty -- in fact the
user just cleared it, because we got here from an input event on
it -- but the compose box is still open to some PM thread that we
have a typing notification still outstanding for.
The old behavior is that in this situation we would ignore the
fact that the content was empty, and go ahead and prolong the
typing notification, by updating our timer and possibly sending a
"still typing" notice.
This contrasts with the behavior (both old and new) in the case
where the content is empty and we *don't* already have an
outstanding typing notification, or we have one to some other
thread. In that case, we cancel any existing notification and
don't start a new one, exactly as if `stop` were called
(e.g. because the user closed the compose box.)
The new behavior is that we always treat clearing the input as
"stopped typing": not only in those cases where we already did,
but also in the case where we still have the same recipients.
(Which seems like probably the common case.)
That seems like the preferable behavior; indeed it's hard to see
the point of the "compose_empty" logic if restricted to the other
cases. It also makes the interface simpler.
Those two properties don't seem like a coincidence, either: the
complicated interface made it difficult to unpack exactly what
logic we actually had, which made it easy for surprising wrinkles
to hang out indefinitely.
2019-10-21 23:37:22 +02:00
|
|
|
var new_recipient =
|
2019-10-22 02:52:01 +02:00
|
|
|
is_valid_conversation() ? exports.get_recipient() : null;
|
2019-10-22 02:38:51 +02:00
|
|
|
typing_status.update(worker, new_recipient);
|
2018-03-16 12:39:46 +01:00
|
|
|
});
|
2017-03-22 00:41:09 +01:00
|
|
|
|
2018-03-16 12:39:46 +01:00
|
|
|
// We send a stop-typing notification immediately when compose is
|
|
|
|
// closed/cancelled
|
|
|
|
$(document).on('compose_canceled.zulip compose_finished.zulip', function () {
|
2019-10-22 02:52:01 +02:00
|
|
|
typing_status.update(worker, null);
|
2018-03-16 12:39:46 +01:00
|
|
|
});
|
|
|
|
};
|
2016-10-12 20:57:59 +02:00
|
|
|
|
|
|
|
return exports;
|
|
|
|
}());
|
|
|
|
|
|
|
|
if (typeof module !== 'undefined') {
|
|
|
|
module.exports = typing;
|
|
|
|
}
|
2018-05-28 08:04:36 +02:00
|
|
|
window.typing = typing;
|