diff --git a/frontend_tests/node_tests/dispatch.js b/frontend_tests/node_tests/dispatch.js
index d57a12e086..baf57ad4c2 100644
--- a/frontend_tests/node_tests/dispatch.js
+++ b/frontend_tests/node_tests/dispatch.js
@@ -667,6 +667,16 @@ run_test("user_settings", ({override}) => {
dispatch(event);
assert_same(user_settings.left_side_userlist, true);
+ event = event_fixtures.user_settings__escape_navigates_to_default_view;
+ user_settings.escape_navigates_to_default_view = false;
+ let toggled = [];
+ $("#go-to-default-view-hotkey-help").toggleClass = (cls) => {
+ toggled.push(cls);
+ };
+ dispatch(event);
+ assert_same(user_settings.escape_navigates_to_default_view, true);
+ assert_same(toggled, ["notdisplayed"]);
+
// We alias message_list.narrowed to message_lists.current
// to make sure we get line coverage on re-rendering
// the current message list. The actual code tests
@@ -694,7 +704,7 @@ run_test("user_settings", ({override}) => {
event = event_fixtures.user_settings__high_contrast_mode;
user_settings.high_contrast_mode = false;
- let toggled = [];
+ toggled = [];
$("body").toggleClass = (cls) => {
toggled.push(cls);
};
diff --git a/frontend_tests/node_tests/lib/events.js b/frontend_tests/node_tests/lib/events.js
index 177ad51451..dab3c5b25b 100644
--- a/frontend_tests/node_tests/lib/events.js
+++ b/frontend_tests/node_tests/lib/events.js
@@ -797,6 +797,13 @@ exports.fixtures = {
value: true,
},
+ user_settings__escape_navigates_to_default_view: {
+ type: "user_settings",
+ op: "update",
+ property: "escape_navigates_to_default_view",
+ value: true,
+ },
+
user_settings__fluid_layout_width: {
type: "user_settings",
op: "update",
diff --git a/static/js/hotkey.js b/static/js/hotkey.js
index b457f9d8b9..e0930f34f3 100644
--- a/static/js/hotkey.js
+++ b/static/js/hotkey.js
@@ -40,6 +40,7 @@ import * as stream_popover from "./stream_popover";
import * as stream_settings_ui from "./stream_settings_ui";
import * as topic_zoom from "./topic_zoom";
import * as ui from "./ui";
+import {user_settings} from "./user_settings";
function do_narrow_action(action) {
action(message_lists.current.selected_id(), {trigger: "hotkey"});
@@ -329,8 +330,14 @@ export function process_escape_key(e) {
return true;
}
- hashchange.set_hash_to_default_view();
- return true;
+ /* The Ctrl+[ hotkey navigates to the default view
+ * unconditionally; Esc's behavior depends on a setting. */
+ if (user_settings.escape_navigates_to_default_view || e.which === 219) {
+ hashchange.set_hash_to_default_view();
+ return true;
+ }
+
+ return false;
}
function handle_popover_events(event_name) {
diff --git a/static/js/info_overlay.js b/static/js/info_overlay.js
index 8fea448e08..8b16fb38bb 100644
--- a/static/js/info_overlay.js
+++ b/static/js/info_overlay.js
@@ -13,6 +13,7 @@ import * as markdown from "./markdown";
import * as overlays from "./overlays";
import * as rendered_markdown from "./rendered_markdown";
import * as ui from "./ui";
+import {user_settings} from "./user_settings";
import * as util from "./util";
// Make it explicit that our toggler is undefined until
@@ -210,6 +211,10 @@ export function set_up_toggler() {
$(".informational-overlays .overlay-tabs").append(elem);
+ $("#go-to-default-view-hotkey-help").toggleClass(
+ "notdisplayed",
+ !user_settings.escape_navigates_to_default_view,
+ );
common.adjust_mac_shortcuts(".hotkeys_table .hotkey kbd");
common.adjust_mac_shortcuts("#markdown-instructions kbd");
}
diff --git a/static/js/realm_user_settings_defaults.ts b/static/js/realm_user_settings_defaults.ts
index 8ecdb9b0c8..cd2a1104fd 100644
--- a/static/js/realm_user_settings_defaults.ts
+++ b/static/js/realm_user_settings_defaults.ts
@@ -21,6 +21,7 @@ export type RealmDefaultSettingsType = {
enable_stream_email_notifications: boolean;
enable_stream_push_notifications: boolean;
enter_sends: boolean;
+ escape_navigates_to_default_view: boolean;
fluid_layout_width: boolean;
high_contrast_mode: boolean;
left_side_userlist: boolean;
diff --git a/static/js/server_events_dispatch.js b/static/js/server_events_dispatch.js
index 54ffd4eb24..b6996e73fc 100644
--- a/static/js/server_events_dispatch.js
+++ b/static/js/server_events_dispatch.js
@@ -576,6 +576,7 @@ export function dispatch_normal_event(event) {
"demote_inactive_streams",
"dense_mode",
"emojiset",
+ "escape_navigates_to_default_view",
"fluid_layout_width",
"high_contrast_mode",
"left_side_userlist",
@@ -673,6 +674,10 @@ export function dispatch_normal_event(event) {
$("#user_presence_enabled").prop("checked", user_settings.presence_enabled);
break;
}
+ if (event.property === "escape_navigates_to_default_view") {
+ $("#go-to-default-view-hotkey-help").toggleClass("notdisplayed", !event.value);
+ break;
+ }
settings_display.update_page(settings_display.user_settings_panel);
break;
}
diff --git a/static/js/settings_config.ts b/static/js/settings_config.ts
index 78228b57ee..94c6b325bc 100644
--- a/static/js/settings_config.ts
+++ b/static/js/settings_config.ts
@@ -434,6 +434,7 @@ export const display_settings_labels = {
defaultMessage: "Convert emoticons before sending (:)
becomes 😃)",
}),
),
+ escape_navigates_to_default_view: $t({defaultMessage: "Escape key navigates to default view"}),
};
export const notification_settings_labels = {
diff --git a/static/js/settings_display.js b/static/js/settings_display.js
index 46f5f2630b..c3a2a43e3f 100644
--- a/static/js/settings_display.js
+++ b/static/js/settings_display.js
@@ -47,16 +47,14 @@ export function set_up(settings_panel) {
container.find(".advanced-settings-status").hide();
+ // Select current values for enum/select type fields. For boolean
+ // fields, the current value is set automatically in the template.
container.find(".setting_demote_inactive_streams").val(settings_object.demote_inactive_streams);
-
container.find(".setting_color_scheme").val(settings_object.color_scheme);
-
container.find(".setting_default_view").val(settings_object.default_view);
-
container
.find(".setting_twenty_four_hour_time")
.val(JSON.stringify(settings_object.twenty_four_hour_time));
-
container
.find(`.setting_emojiset_choice[value="${CSS.escape(settings_object.emojiset)}"]`)
.prop("checked", true);
@@ -186,9 +184,15 @@ export function update_page(settings_panel) {
const container = $(settings_panel.container);
const settings_object = settings_panel.settings_object;
+ // Boolean fields
container.find(".left_side_userlist").prop("checked", settings_object.left_side_userlist);
- container.find(".default_language_name").text(default_language_name);
container.find(".translate_emoticons").prop("checked", settings_object.translate_emoticons);
+ container
+ .find(".escape_navigates_to_default_view")
+ .prop("checked", settings_object.escape_navigates_to_default_view);
+
+ // Enum/select fields
+ container.find(".default_language_name").text(default_language_name);
container
.find(".setting_twenty_four_hour_time")
.val(JSON.stringify(settings_object.twenty_four_hour_time));
diff --git a/static/js/user_settings.ts b/static/js/user_settings.ts
index 88ce89c4f5..bb6bbff0fc 100644
--- a/static/js/user_settings.ts
+++ b/static/js/user_settings.ts
@@ -21,6 +21,7 @@ export type UserSettingsType = {
enable_stream_email_notifications: boolean;
enable_stream_push_notifications: boolean;
enter_sends: boolean;
+ escape_navigates_to_default_view: boolean;
fluid_layout_width: boolean;
high_contrast_mode: boolean;
left_side_userlist: boolean;
diff --git a/static/styles/settings.css b/static/styles/settings.css
index 11c0e6b9b3..dd40764540 100644
--- a/static/styles/settings.css
+++ b/static/styles/settings.css
@@ -430,8 +430,10 @@ td .button {
}
.input-group {
- .thinner {
- margin: 10px 0;
+ /* Class to use when the following input-group is related and should
+ appear just after this element. */
+ &.thinner {
+ margin: 0;
}
label.checkbox + label {
diff --git a/static/templates/keyboard_shortcuts.hbs b/static/templates/keyboard_shortcuts.hbs
index bf523487bc..32cfe2bfc7 100644
--- a/static/templates/keyboard_shortcuts.hbs
+++ b/static/templates/keyboard_shortcuts.hbs
@@ -54,7 +54,7 @@
{{t 'Go to default view' }} |
- Esc or Ctrl + [ |
+ Ctrl + [ or Esc |
diff --git a/static/templates/settings/display_settings.hbs b/static/templates/settings/display_settings.hbs
index 8025a49b43..1c594b61f0 100644
--- a/static/templates/settings/display_settings.hbs
+++ b/static/templates/settings/display_settings.hbs
@@ -80,15 +80,21 @@
{{> settings_save_discard_widget section_name="advanced-settings" show_only_indicator=(not for_realm_settings) }}
-
+
+ {{> settings_checkbox
+ setting_name="escape_navigates_to_default_view"
+ is_checked=settings_object.escape_navigates_to_default_view
+ label=settings_label.escape_navigates_to_default_view
+ prefix=prefix}}
+