mirror of https://github.com/zulip/zulip.git
hotkey: Add 'narrow to next unread followed topic' hotkey.
This commit adds a 'Shift + N' keyboard shortcut, which is used to narrow to the next unread followed topic. Fixes part of #27323.
This commit is contained in:
parent
6819ecee92
commit
8e2264b585
|
@ -14,7 +14,8 @@
|
|||
|
||||
!!! keyboard_tip ""
|
||||
|
||||
Use the <kbd>N</kbd> key to go to the next unread topic, or <kbd>P</kbd>
|
||||
to go to the next unread direct message conversation.
|
||||
Use the <kbd>N</kbd> key to go to the next unread topic, or <kbd>Shift</kbd> + <kbd>N</kbd>
|
||||
for the next unread [followed](/help/follow-a-topic) topic, or <kbd>P</kbd> for the next
|
||||
unread direct message conversation.
|
||||
|
||||
{end_tabs}
|
||||
|
|
|
@ -38,6 +38,8 @@ in the Zulip app to add more to your repertoire as needed.
|
|||
|
||||
* **Next unread topic**: <kbd>N</kbd>
|
||||
|
||||
* **Next unread followed topic**: <kbd>Shift</kbd> + <kbd>N</kbd>
|
||||
|
||||
* **Next unread direct message**: <kbd>P</kbd>
|
||||
|
||||
* **Search messages**: <kbd>/</kbd>
|
||||
|
|
|
@ -88,6 +88,7 @@ const keydown_shift_mappings = {
|
|||
38: {name: "up_arrow", message_view_only: false}, // up arrow
|
||||
40: {name: "down_arrow", message_view_only: false}, // down arrow
|
||||
72: {name: "view_edit_history", message_view_only: true}, // 'H'
|
||||
78: {name: "narrow_to_next_unread_followed_topic", message_view_only: false}, // 'N'
|
||||
};
|
||||
|
||||
const keydown_unshift_mappings = {
|
||||
|
@ -904,7 +905,10 @@ export function process_hotkey(e, hotkey) {
|
|||
narrow.stream_cycle_forward();
|
||||
return true;
|
||||
case "n_key":
|
||||
narrow.narrow_to_next_topic({trigger: "hotkey"});
|
||||
narrow.narrow_to_next_topic({trigger: "hotkey", only_followed_topics: false});
|
||||
return true;
|
||||
case "narrow_to_next_unread_followed_topic":
|
||||
narrow.narrow_to_next_topic({trigger: "hotkey", only_followed_topics: true});
|
||||
return true;
|
||||
case "p_key":
|
||||
narrow.narrow_to_next_pm_string({trigger: "hotkey"});
|
||||
|
|
|
@ -770,7 +770,11 @@ export function narrow_to_next_topic(opts = {}) {
|
|||
topic: narrow_state.topic(),
|
||||
};
|
||||
|
||||
const next_narrow = topic_generator.get_next_topic(curr_info.stream, curr_info.topic);
|
||||
const next_narrow = topic_generator.get_next_topic(
|
||||
curr_info.stream,
|
||||
curr_info.topic,
|
||||
opts.only_followed_topics,
|
||||
);
|
||||
|
||||
if (!next_narrow) {
|
||||
return;
|
||||
|
|
|
@ -49,7 +49,7 @@ export function next_topic(streams, get_topics, has_unread_messages, curr_stream
|
|||
return undefined;
|
||||
}
|
||||
|
||||
export function get_next_topic(curr_stream, curr_topic) {
|
||||
export function get_next_topic(curr_stream, curr_topic, only_followed_topics) {
|
||||
let my_streams = stream_list_sort.get_streams();
|
||||
|
||||
my_streams = my_streams.filter((stream_name) => {
|
||||
|
@ -71,11 +71,28 @@ export function get_next_topic(curr_stream, curr_topic) {
|
|||
return topics;
|
||||
}
|
||||
|
||||
function get_followed_topics(stream_name) {
|
||||
const stream_id = stream_data.get_stream_id(stream_name);
|
||||
let topics = stream_topic_history.get_recent_topic_names(stream_id);
|
||||
topics = topics.filter((topic) => user_topics.is_topic_followed(stream_id, topic));
|
||||
return topics;
|
||||
}
|
||||
|
||||
function has_unread_messages(stream_name, topic) {
|
||||
const stream_id = stream_data.get_stream_id(stream_name);
|
||||
return unread.topic_has_any_unread(stream_id, topic);
|
||||
}
|
||||
|
||||
if (only_followed_topics) {
|
||||
return next_topic(
|
||||
my_streams,
|
||||
get_followed_topics,
|
||||
has_unread_messages,
|
||||
curr_stream,
|
||||
curr_topic,
|
||||
);
|
||||
}
|
||||
|
||||
return next_topic(my_streams, get_unmuted_topics, has_unread_messages, curr_stream, curr_topic);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,10 @@
|
|||
<td class="definition">{{t 'Next unread topic' }}</td>
|
||||
<td><span class="hotkey"><kbd>N</kbd></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="definition">{{t 'Next unread followed topic' }}</td>
|
||||
<td><span class="hotkey"><kbd>Shift</kbd> + <kbd>N</kbd></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="definition">{{t 'Next unread direct message' }}</td>
|
||||
<td><span class="hotkey"><kbd>P</kbd></span></td>
|
||||
|
|
|
@ -182,6 +182,7 @@ run_test("mappings", () => {
|
|||
assert.equal(map_down(13).name, "enter");
|
||||
assert.equal(map_down(46).name, "delete");
|
||||
assert.equal(map_down(13, true).name, "enter");
|
||||
assert.equal(map_down(78, true).name, "narrow_to_next_unread_followed_topic");
|
||||
|
||||
assert.equal(map_press(47).name, "search"); // slash
|
||||
assert.equal(map_press(106).name, "vim_down"); // j
|
||||
|
@ -231,11 +232,15 @@ run_test("mappings", () => {
|
|||
navigator.platform = "";
|
||||
});
|
||||
|
||||
function process(s) {
|
||||
function process(s, shiftKey, keydown = false) {
|
||||
const e = {
|
||||
which: s.codePointAt(0),
|
||||
shiftKey,
|
||||
};
|
||||
try {
|
||||
if (keydown) {
|
||||
return hotkey.process_keydown(e);
|
||||
}
|
||||
return hotkey.process_keypress(e);
|
||||
} catch (error) /* istanbul ignore next */ {
|
||||
// An exception will be thrown here if a different
|
||||
|
@ -247,9 +252,9 @@ function process(s) {
|
|||
}
|
||||
}
|
||||
|
||||
function assert_mapping(c, module, func_name, shiftKey) {
|
||||
function assert_mapping(c, module, func_name, shiftKey, keydown) {
|
||||
stubbing(module, func_name, (stub) => {
|
||||
assert.ok(process(c, shiftKey));
|
||||
assert.ok(process(c, shiftKey, keydown));
|
||||
assert.equal(stub.num_calls, 1);
|
||||
});
|
||||
}
|
||||
|
@ -442,6 +447,10 @@ run_test("n/p keys", () => {
|
|||
assert_mapping("n", narrow, "narrow_to_next_topic");
|
||||
});
|
||||
|
||||
run_test("narrow next unread followed topic", () => {
|
||||
assert_mapping("N", narrow, "narrow_to_next_topic", true, true);
|
||||
});
|
||||
|
||||
run_test("motion_keys", () => {
|
||||
const codes = {
|
||||
down_arrow: 40,
|
||||
|
|
|
@ -89,9 +89,9 @@ run_test("topics", ({override}) => {
|
|||
override(stream_topic_history, "get_recent_topic_names", (stream_id) => {
|
||||
switch (stream_id) {
|
||||
case muted_stream_id:
|
||||
return ["ms-topic1", "ms-topic2"];
|
||||
return ["ms-topic1", "ms-topic2", "followed"];
|
||||
case devel_stream_id:
|
||||
return ["muted", "python"];
|
||||
return ["muted", "python", "followed"];
|
||||
}
|
||||
|
||||
return [];
|
||||
|
@ -107,12 +107,26 @@ run_test("topics", ({override}) => {
|
|||
|
||||
override(user_topics, "is_topic_muted", (_stream_name, topic) => topic === "muted");
|
||||
|
||||
override(user_topics, "is_topic_followed", (_stream_name, topic) => topic === "followed");
|
||||
|
||||
let next_item = tg.get_next_topic("announce", "whatever");
|
||||
assert.deepEqual(next_item, {
|
||||
stream: "devel",
|
||||
topic: "python",
|
||||
});
|
||||
|
||||
next_item = tg.get_next_topic("devel", "python");
|
||||
assert.deepEqual(next_item, {
|
||||
stream: "devel",
|
||||
topic: "followed",
|
||||
});
|
||||
|
||||
next_item = tg.get_next_topic("muted", "whatever", true);
|
||||
assert.deepEqual(next_item, {
|
||||
stream: "muted",
|
||||
topic: "followed",
|
||||
});
|
||||
|
||||
next_item = tg.get_next_topic("muted", undefined);
|
||||
assert.deepEqual(next_item, {
|
||||
stream: "muted",
|
||||
|
|
Loading…
Reference in New Issue