mirror of
https://github.com/zulip/zulip.git
synced 2025-11-19 14:08:23 +00:00
We now do all of the main logic for starring/unstarring
a message in `message_flags.toggle_starred`:
* mark the message as read (just in case)
* update the UI (i.e. the green star in the message)
* update the server
The calling code in both the click handler and the hotkey
handler remains simple--they just handle minor details like
finding the message and clearing popovers.
For updating the server, we now call the new
`send_flag_update` helper.
And we continue to delegate some of the logic to
`ui.update_starred`, but we remove some code there that's
now pushed up to `message_flags.toggle_starred`.
This change should be mostly transparent to users, but it
does remove some inconsistent behaviors between the click
handler and the hotkey handler. Before this change, the
click handler was more aggressive about updating the UI
and marking the message as read. For people using the "*"
key to star/unstar, they probably would only have noticed
different behavior on a slow connection or in an edge
case scenario where only half of the message was onscreen.
More importantly, by simplifying how we talk to the server,
this eliminated up to a one-second lag due to the debounce
logic in the batch_updater code. The complicated debounce
logic is only really needed for batch-updating "read"
messages, and it was overkill and sluggish for starring
messages.
Last but not least, we add defensive code for the local
echo case. (Users have to wait till the message gets acked
to star it.)
136 lines
3.4 KiB
JavaScript
136 lines
3.4 KiB
JavaScript
var message_flags = (function () {
|
|
var exports = {};
|
|
|
|
function send_flag_update(message, flag, op) {
|
|
channel.post({
|
|
url: '/json/messages/flags',
|
|
idempotent: true,
|
|
data: {
|
|
messages: JSON.stringify([message.id]),
|
|
flag: flag,
|
|
op: op,
|
|
},
|
|
});
|
|
}
|
|
|
|
var batched_updaters = {};
|
|
|
|
function batched_updater(flag, op, immediate) {
|
|
var queue = [];
|
|
var on_success;
|
|
var start;
|
|
|
|
function server_request() {
|
|
// Wait for server IDs before sending flags
|
|
var real_msgs = _.filter(queue, function (msg) {
|
|
return !msg.locally_echoed;
|
|
});
|
|
var real_msg_ids = _.map(real_msgs, function (msg) {
|
|
return msg.id;
|
|
});
|
|
|
|
if (real_msg_ids.length === 0) {
|
|
setTimeout(start, 100);
|
|
return;
|
|
}
|
|
|
|
// We have some real IDs. If there are any left in the queue when this
|
|
// call finishes, they will be handled in the success callback.
|
|
|
|
channel.post({
|
|
url: '/json/messages/flags',
|
|
idempotent: true,
|
|
data: {messages: JSON.stringify(real_msg_ids),
|
|
op: op,
|
|
flag: flag},
|
|
success: on_success,
|
|
});
|
|
}
|
|
|
|
if (immediate) {
|
|
start = server_request;
|
|
} else {
|
|
start = _.debounce(server_request, 1000);
|
|
}
|
|
|
|
on_success = function on_success(data) {
|
|
if (data === undefined || data.messages === undefined) {
|
|
return;
|
|
}
|
|
|
|
queue = _.filter(queue, function (message) {
|
|
return data.messages.indexOf(message.id) === -1;
|
|
});
|
|
|
|
if (queue.length > 0) {
|
|
start();
|
|
}
|
|
};
|
|
|
|
function add(message) {
|
|
if (message.flags === undefined) {
|
|
message.flags = [];
|
|
}
|
|
if (op === 'add') {
|
|
message.flags.push(flag);
|
|
} else {
|
|
message.flags = _.without(message.flags, flag);
|
|
}
|
|
queue.push(message);
|
|
start();
|
|
}
|
|
|
|
return add;
|
|
}
|
|
|
|
exports.send_read = batched_updater('read', 'add');
|
|
|
|
function send_flag(messages, flag_name, set_flag) {
|
|
var op = set_flag ? 'add' : 'remove';
|
|
var flag_key = flag_name + '_' + op;
|
|
var updater;
|
|
|
|
if (batched_updaters.hasOwnProperty(flag_key)) {
|
|
updater = batched_updaters[flag_key];
|
|
} else {
|
|
updater = batched_updater(flag_name, op, true);
|
|
batched_updaters[flag_key] = updater;
|
|
}
|
|
|
|
_.each(messages, function (message) {
|
|
updater(message);
|
|
});
|
|
}
|
|
|
|
exports.send_collapsed = function send_collapse(messages, value) {
|
|
send_flag(messages, "collapsed", value);
|
|
};
|
|
|
|
exports.toggle_starred = function (message) {
|
|
if (message.locally_echoed) {
|
|
// This is defensive code for when you hit the "*" key
|
|
// before we get a server ack. It's rare that somebody
|
|
// can star this quickly, and we don't have a good way
|
|
// to tell the server which message was starred.
|
|
return;
|
|
}
|
|
|
|
message.starred = !message.starred;
|
|
|
|
unread_ops.mark_message_as_read(message);
|
|
ui.update_starred(message);
|
|
|
|
if (message.starred) {
|
|
send_flag_update(message, 'starred', 'add');
|
|
} else {
|
|
send_flag_update(message, 'starred', 'remove');
|
|
}
|
|
};
|
|
|
|
return exports;
|
|
}());
|
|
|
|
if (typeof module !== 'undefined') {
|
|
module.exports = message_flags;
|
|
}
|