mirror of https://github.com/zulip/zulip.git
search: Don't mark messages as read in search narrow.
Don't mark unread messages as read while searching. This behavior will be extended to other narrows later. Fixes: #12556.
This commit is contained in:
parent
bd52ec9f95
commit
6ec40cf9a0
|
@ -99,6 +99,10 @@ These two simple rules, combined with the pointer logic above, end up
|
||||||
matching user expectations well for whether the product should treat
|
matching user expectations well for whether the product should treat
|
||||||
them as having read a set of messages (or not).
|
them as having read a set of messages (or not).
|
||||||
|
|
||||||
|
One key detail to highlight is that we only mark messages as read
|
||||||
|
through these processes in views that contain all messages in a
|
||||||
|
thread; search views will never mark messages as read.
|
||||||
|
|
||||||
## Testing and development
|
## Testing and development
|
||||||
|
|
||||||
In a Zulip development environment, you can use `manage.py
|
In a Zulip development environment, you can use `manage.py
|
||||||
|
|
|
@ -82,6 +82,9 @@ function stub_selected_message(msg) {
|
||||||
selected_message: function () {
|
selected_message: function () {
|
||||||
return msg;
|
return msg;
|
||||||
},
|
},
|
||||||
|
can_mark_messages_read: function () {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ run_test('basics', () => {
|
||||||
assert(!filter.has_operand('stream', 'nada'));
|
assert(!filter.has_operand('stream', 'nada'));
|
||||||
|
|
||||||
assert(!filter.is_search());
|
assert(!filter.is_search());
|
||||||
|
assert(filter.can_mark_messages_read());
|
||||||
assert(filter.can_apply_locally());
|
assert(filter.can_apply_locally());
|
||||||
|
|
||||||
operators = [
|
operators = [
|
||||||
|
@ -78,6 +79,7 @@ run_test('basics', () => {
|
||||||
filter = new Filter(operators);
|
filter = new Filter(operators);
|
||||||
|
|
||||||
assert(filter.is_search());
|
assert(filter.is_search());
|
||||||
|
assert(!filter.can_mark_messages_read());
|
||||||
assert(!filter.can_apply_locally());
|
assert(!filter.can_apply_locally());
|
||||||
assert(!filter.is_exactly('stream'));
|
assert(!filter.is_exactly('stream'));
|
||||||
|
|
||||||
|
|
|
@ -527,8 +527,11 @@ run_test('unread_ops', () => {
|
||||||
// Make us not be in a narrow (somewhat hackily).
|
// Make us not be in a narrow (somewhat hackily).
|
||||||
message_list.narrowed = undefined;
|
message_list.narrowed = undefined;
|
||||||
|
|
||||||
|
// Set current_message_list containing messages that
|
||||||
|
// can be marked read
|
||||||
set_global('current_msg_list', {
|
set_global('current_msg_list', {
|
||||||
all_messages: () => test_messages,
|
all_messages: () => test_messages,
|
||||||
|
can_mark_messages_read: () => true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ignore these interactions for now:
|
// Ignore these interactions for now:
|
||||||
|
@ -544,6 +547,12 @@ run_test('unread_ops', () => {
|
||||||
channel_post_opts = opts;
|
channel_post_opts = opts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// First, test for a message list that cannot read messages
|
||||||
|
current_msg_list.can_mark_messages_read = () => false;
|
||||||
|
unread_ops.process_visible();
|
||||||
|
assert.deepEqual(channel_post_opts, undefined);
|
||||||
|
|
||||||
|
current_msg_list.can_mark_messages_read = () => true;
|
||||||
// Do the main thing we're testing!
|
// Do the main thing we're testing!
|
||||||
unread_ops.process_visible();
|
unread_ops.process_visible();
|
||||||
|
|
||||||
|
@ -556,6 +565,7 @@ run_test('unread_ops', () => {
|
||||||
data: { messages: '[50]', op: 'add', flag: 'read' },
|
data: { messages: '[50]', op: 'add', flag: 'read' },
|
||||||
success: channel_post_opts.success,
|
success: channel_post_opts.success,
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -13,7 +13,10 @@ run_test('starred', () => {
|
||||||
const message = {
|
const message = {
|
||||||
id: 50,
|
id: 50,
|
||||||
};
|
};
|
||||||
|
set_global('current_msg_list', {
|
||||||
|
all_messages: () => [message],
|
||||||
|
is_search: () => false,
|
||||||
|
});
|
||||||
var ui_updated;
|
var ui_updated;
|
||||||
|
|
||||||
ui.update_starred_view = () => {
|
ui.update_starred_view = () => {
|
||||||
|
|
|
@ -37,7 +37,7 @@ run_test('basics', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(mld.is_search(), false);
|
assert.equal(mld.is_search(), false);
|
||||||
|
assert(mld.can_mark_messages_read());
|
||||||
mld.add_anywhere(make_msgs([35, 25, 15, 45]));
|
mld.add_anywhere(make_msgs([35, 25, 15, 45]));
|
||||||
|
|
||||||
assert_contents(mld, [15, 25, 35, 45]);
|
assert_contents(mld, [15, 25, 35, 45]);
|
||||||
|
|
|
@ -301,7 +301,9 @@ exports.respond_to_message = function (opts) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unread_ops.notify_server_message_read(message);
|
if (current_msg_list.can_mark_messages_read()) {
|
||||||
|
unread_ops.notify_server_message_read(message);
|
||||||
|
}
|
||||||
|
|
||||||
var stream = '';
|
var stream = '';
|
||||||
var topic = '';
|
var topic = '';
|
||||||
|
|
|
@ -375,6 +375,10 @@ Filter.prototype = {
|
||||||
return this.has_operator('search');
|
return this.has_operator('search');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
can_mark_messages_read: function () {
|
||||||
|
return !this.has_operator('search');
|
||||||
|
},
|
||||||
|
|
||||||
can_apply_locally: function () {
|
can_apply_locally: function () {
|
||||||
if (this.is_search()) {
|
if (this.is_search()) {
|
||||||
// The semantics for matching keywords are implemented
|
// The semantics for matching keywords are implemented
|
||||||
|
|
|
@ -101,6 +101,10 @@ exports.toggle_starred_and_update_server = function (message) {
|
||||||
|
|
||||||
message.starred = !message.starred;
|
message.starred = !message.starred;
|
||||||
|
|
||||||
|
// Unlike most calls to mark messages as read, we don't check
|
||||||
|
// msg_list.can_mark_messages_read, because starring a message is an
|
||||||
|
// explicit interaction and we'd like to preserve the user
|
||||||
|
// expectation invariant that all starred messages are read.
|
||||||
unread_ops.notify_server_message_read(message);
|
unread_ops.notify_server_message_read(message);
|
||||||
ui.update_starred_view(message.id, message.starred);
|
ui.update_starred_view(message.id, message.starred);
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,10 @@ exports.MessageList.prototype = {
|
||||||
return this.data.is_search();
|
return this.data.is_search();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
can_mark_messages_read: function () {
|
||||||
|
return this.data.can_mark_messages_read();
|
||||||
|
},
|
||||||
|
|
||||||
clear: function MessageList_clear(opts) {
|
clear: function MessageList_clear(opts) {
|
||||||
opts = _.extend({clear_selected_id: true}, opts);
|
opts = _.extend({clear_selected_id: true}, opts);
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,9 @@ MessageListData.prototype = {
|
||||||
is_search: function () {
|
is_search: function () {
|
||||||
return this.filter.is_search();
|
return this.filter.is_search();
|
||||||
},
|
},
|
||||||
|
can_mark_messages_read: function () {
|
||||||
|
return this.filter.can_mark_messages_read();
|
||||||
|
},
|
||||||
_get_predicate: function () {
|
_get_predicate: function () {
|
||||||
// We cache this.
|
// We cache this.
|
||||||
if (!this.predicate) {
|
if (!this.predicate) {
|
||||||
|
|
|
@ -592,7 +592,12 @@ exports.by_topic = function (target_id, opts) {
|
||||||
exports.by_recipient(target_id, opts);
|
exports.by_recipient(target_id, opts);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't check msg_list.can_mark_messages_read here only because
|
||||||
|
// the target msg_list isn't initialized yet; in any case, the
|
||||||
|
// message is about to be marked read in the new view.
|
||||||
unread_ops.notify_server_message_read(original);
|
unread_ops.notify_server_message_read(original);
|
||||||
|
|
||||||
var search_terms = [
|
var search_terms = [
|
||||||
{operator: 'stream', operand: original.stream},
|
{operator: 'stream', operand: original.stream},
|
||||||
{operator: 'topic', operand: util.get_message_topic(original)},
|
{operator: 'topic', operand: util.get_message_topic(original)},
|
||||||
|
@ -606,7 +611,12 @@ exports.by_recipient = function (target_id, opts) {
|
||||||
opts = _.defaults({}, opts, {then_select_id: target_id});
|
opts = _.defaults({}, opts, {then_select_id: target_id});
|
||||||
// don't use current_msg_list as it won't work for muted messages or for out-of-narrow links
|
// don't use current_msg_list as it won't work for muted messages or for out-of-narrow links
|
||||||
var message = message_store.get(target_id);
|
var message = message_store.get(target_id);
|
||||||
|
|
||||||
|
// We don't check msg_list.can_mark_messages_read here only because
|
||||||
|
// the target msg_list isn't initialized yet; in any case, the
|
||||||
|
// message is about to be marked read in the new view.
|
||||||
unread_ops.notify_server_message_read(message);
|
unread_ops.notify_server_message_read(message);
|
||||||
|
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case 'private':
|
case 'private':
|
||||||
exports.by('pm-with', message.reply_to, opts);
|
exports.by('pm-with', message.reply_to, opts);
|
||||||
|
|
|
@ -28,7 +28,9 @@ exports.down = function (with_centering) {
|
||||||
var current_msg_table = rows.get_table(current_msg_list.table_name);
|
var current_msg_table = rows.get_table(current_msg_list.table_name);
|
||||||
message_viewport.scrollTop(current_msg_table.safeOuterHeight(true) -
|
message_viewport.scrollTop(current_msg_table.safeOuterHeight(true) -
|
||||||
message_viewport.height() * 0.1);
|
message_viewport.height() * 0.1);
|
||||||
unread_ops.mark_current_list_as_read();
|
if (current_msg_list.can_mark_messages_read()) {
|
||||||
|
unread_ops.mark_current_list_as_read();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -54,7 +56,9 @@ exports.to_end = function () {
|
||||||
message_viewport.set_last_movement_direction(1);
|
message_viewport.set_last_movement_direction(1);
|
||||||
current_msg_list.select_id(next_id, {then_scroll: true,
|
current_msg_list.select_id(next_id, {then_scroll: true,
|
||||||
from_scroll: true});
|
from_scroll: true});
|
||||||
unread_ops.mark_current_list_as_read();
|
if (current_msg_list.can_mark_messages_read()) {
|
||||||
|
unread_ops.mark_current_list_as_read();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function amount_to_paginate() {
|
function amount_to_paginate() {
|
||||||
|
@ -114,7 +118,9 @@ exports.page_up = function () {
|
||||||
exports.page_down = function () {
|
exports.page_down = function () {
|
||||||
if (message_viewport.at_bottom() && !current_msg_list.empty()) {
|
if (message_viewport.at_bottom() && !current_msg_list.empty()) {
|
||||||
current_msg_list.select_id(current_msg_list.last().id, {then_scroll: false});
|
current_msg_list.select_id(current_msg_list.last().id, {then_scroll: false});
|
||||||
unread_ops.mark_current_list_as_read();
|
if (current_msg_list.can_mark_messages_read()) {
|
||||||
|
unread_ops.mark_current_list_as_read();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
exports.page_down_the_right_amount();
|
exports.page_down_the_right_amount();
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,9 @@ exports.initialize = function initialize() {
|
||||||
} else {
|
} else {
|
||||||
messages = event.msg_list.message_range(event.previously_selected, event.id);
|
messages = event.msg_list.message_range(event.previously_selected, event.id);
|
||||||
}
|
}
|
||||||
unread_ops.notify_server_messages_read(messages, {from: 'pointer'});
|
if (event.msg_list.can_mark_messages_read()) {
|
||||||
|
unread_ops.notify_server_messages_read(messages, {from: 'pointer'});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,7 +60,6 @@ exports.process_read_messages_event = function (message_ids) {
|
||||||
// Skips any messages that are already marked as read.
|
// Skips any messages that are already marked as read.
|
||||||
exports.notify_server_messages_read = function (messages, options) {
|
exports.notify_server_messages_read = function (messages, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
messages = unread.get_unread_messages(messages);
|
messages = unread.get_unread_messages(messages);
|
||||||
if (messages.length === 0) {
|
if (messages.length === 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -91,7 +90,8 @@ exports.process_visible = function () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message_viewport.bottom_message_visible()) {
|
if (message_viewport.bottom_message_visible() &&
|
||||||
|
current_msg_list.can_mark_messages_read()) {
|
||||||
exports.mark_current_list_as_read();
|
exports.mark_current_list_as_read();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue