mirror of https://github.com/zulip/zulip.git
tooltips: Add support for modifier key conversion for mac-syle keyboards.
We scan a tooltip for any required windows-to-mac hotkey conversions from the list of attributes supplied to the hotkey_hints helper. If we find any, we add/modify the hotkyes in the hotkey hints list to match the mac-style key combinations and then return back the modified list of hotkey hints to be displayed in the tooltip. We also rename the "adjust_mac_shortcuts" function, used for the keyboard shortcuts menu and help center documnets, to "adjust_mac_kbd_tags" to avoid any ambiguity with the adjust_mac_tooltip_keys funtion which is used for tooltip hotkeys.
This commit is contained in:
parent
df04063bf4
commit
0f213f13ff
|
@ -80,16 +80,16 @@ run_test("copy_data_attribute_value", ({override}) => {
|
||||||
assert.ok(faded_out);
|
assert.ok(faded_out);
|
||||||
});
|
});
|
||||||
|
|
||||||
run_test("adjust_mac_shortcuts non-mac", ({override}) => {
|
run_test("adjust_mac_kbd_tags non-mac", ({override}) => {
|
||||||
override(navigator, "platform", "Windows");
|
override(navigator, "platform", "Windows");
|
||||||
|
|
||||||
// The adjust_mac_shortcuts has a really simple guard
|
// The adjust_mac_kbd_tags has a really simple guard
|
||||||
// at the top, and we just test the early-return behavior
|
// at the top, and we just test the early-return behavior
|
||||||
// by trying to pass it garbage.
|
// by trying to pass it garbage.
|
||||||
common.adjust_mac_shortcuts("selector-that-does-not-exist");
|
common.adjust_mac_kbd_tags("selector-that-does-not-exist");
|
||||||
});
|
});
|
||||||
|
|
||||||
run_test("adjust_mac_shortcuts mac", ({override}) => {
|
run_test("adjust_mac_kbd_tags mac", ({override}) => {
|
||||||
const keys_to_test_mac = new Map([
|
const keys_to_test_mac = new Map([
|
||||||
["Backspace", "Delete"],
|
["Backspace", "Delete"],
|
||||||
["Enter", "Return"],
|
["Enter", "Return"],
|
||||||
|
@ -134,7 +134,7 @@ run_test("adjust_mac_shortcuts mac", ({override}) => {
|
||||||
|
|
||||||
$.create(".markdown kbd", {children});
|
$.create(".markdown kbd", {children});
|
||||||
|
|
||||||
common.adjust_mac_shortcuts(".markdown kbd");
|
common.adjust_mac_kbd_tags(".markdown kbd");
|
||||||
|
|
||||||
for (const test_item of test_items) {
|
for (const test_item of test_items) {
|
||||||
assert.equal(test_item.$stub.text(), test_item.mac_key);
|
assert.equal(test_item.$stub.text(), test_item.mac_key);
|
||||||
|
@ -142,6 +142,92 @@ run_test("adjust_mac_shortcuts mac", ({override}) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
run_test("adjust_mac_tooltip_keys non-mac", ({override}) => {
|
||||||
|
override(navigator, "platform", "Windows");
|
||||||
|
|
||||||
|
// The adjust_mac_tooltip_keys has a really simple guard
|
||||||
|
// at the top, and we just test the early-return behavior
|
||||||
|
// by trying to pass it garbage.
|
||||||
|
common.adjust_mac_tooltip_keys("not-an-array");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test default values of adjust_mac_tooltip_keys
|
||||||
|
// Expected values
|
||||||
|
run_test("adjust_mac_tooltip_keys mac expected", ({override}) => {
|
||||||
|
const keys_to_test_mac = new Map([
|
||||||
|
[["Backspace"], ["Delete"]],
|
||||||
|
[["Enter"], ["Return"]],
|
||||||
|
[["Home"], ["Fn", "←"]],
|
||||||
|
[["End"], ["Fn", "→"]],
|
||||||
|
[["PgUp"], ["Fn", "↑"]],
|
||||||
|
[["PgDn"], ["Fn", "↓"]],
|
||||||
|
[["Ctrl"], ["⌘"]],
|
||||||
|
[["Alt"], ["⌘"]],
|
||||||
|
]);
|
||||||
|
|
||||||
|
override(navigator, "platform", "MacIntel");
|
||||||
|
|
||||||
|
const test_items = [];
|
||||||
|
|
||||||
|
for (const [old_key, mac_key] of keys_to_test_mac) {
|
||||||
|
const test_item = {};
|
||||||
|
common.adjust_mac_tooltip_keys(old_key);
|
||||||
|
|
||||||
|
test_item.mac_key = mac_key;
|
||||||
|
test_item.adjusted_key = old_key;
|
||||||
|
test_items.push(test_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const test_item of test_items) {
|
||||||
|
assert.deepStrictEqual(test_item.mac_key, test_item.adjusted_key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test non-default values of adjust_mac_tooltip_keys
|
||||||
|
// Random values
|
||||||
|
run_test("adjust_mac_tooltip_keys mac random", ({override}) => {
|
||||||
|
const keys_to_test_mac = new Map([
|
||||||
|
[
|
||||||
|
["Ctrl", "["],
|
||||||
|
["⌘", "["],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
["Ctrl", "K"],
|
||||||
|
["⌘", "K"],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
["Shift", "G"],
|
||||||
|
["Shift", "G"],
|
||||||
|
],
|
||||||
|
[["Space"], ["Space"]],
|
||||||
|
[
|
||||||
|
["Alt", "←"],
|
||||||
|
["⌘", "←"],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
["Alt", "→"],
|
||||||
|
["⌘", "→"],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
override(navigator, "platform", "MacIntel");
|
||||||
|
|
||||||
|
const test_items = [];
|
||||||
|
|
||||||
|
for (const [old_key, mac_key] of keys_to_test_mac) {
|
||||||
|
const test_item = {};
|
||||||
|
common.adjust_mac_tooltip_keys(old_key);
|
||||||
|
|
||||||
|
test_item.mac_key = mac_key;
|
||||||
|
test_item.adjusted_key = old_key;
|
||||||
|
test_items.push(test_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const test_item of test_items) {
|
||||||
|
assert.deepStrictEqual(test_item.mac_key, test_item.adjusted_key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
run_test("show password", () => {
|
run_test("show password", () => {
|
||||||
const password_selector = "#id_password ~ .password_visibility_toggle";
|
const password_selector = "#id_password ~ .password_visibility_toggle";
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,9 @@ process.env.NODE_ENV = "test";
|
||||||
|
|
||||||
const dom = new JSDOM("", {url: "http://zulip.zulipdev.com/"});
|
const dom = new JSDOM("", {url: "http://zulip.zulipdev.com/"});
|
||||||
global.DOMParser = dom.window.DOMParser;
|
global.DOMParser = dom.window.DOMParser;
|
||||||
|
global.navigator = {
|
||||||
|
userAgent: "node.js",
|
||||||
|
};
|
||||||
|
|
||||||
require("@babel/register")({
|
require("@babel/register")({
|
||||||
extensions: [".es6", ".es", ".jsx", ".js", ".mjs", ".ts"],
|
extensions: [".es6", ".es", ".jsx", ".js", ".mjs", ".ts"],
|
||||||
|
|
|
@ -44,28 +44,30 @@ export function copy_data_attribute_value($elem: JQuery, key: string): void {
|
||||||
$elem.fadeIn(1000);
|
$elem.fadeIn(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const keys_map = new Map([
|
||||||
|
["Backspace", "Delete"],
|
||||||
|
["Enter", "Return"],
|
||||||
|
["Home", "←"],
|
||||||
|
["End", "→"],
|
||||||
|
["PgUp", "↑"],
|
||||||
|
["PgDn", "↓"],
|
||||||
|
["Ctrl", "⌘"],
|
||||||
|
["Alt", "⌘"],
|
||||||
|
]);
|
||||||
|
|
||||||
|
const fn_shortcuts = new Set(["Home", "End", "PgUp", "PgDn"]);
|
||||||
|
|
||||||
export function has_mac_keyboard(): boolean {
|
export function has_mac_keyboard(): boolean {
|
||||||
return /mac/i.test(navigator.platform);
|
return /mac/i.test(navigator.platform);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function adjust_mac_shortcuts(kbd_elem_class: string): void {
|
// We convert the <kbd> tags used for keyboard shortcuts to mac equivalent
|
||||||
|
// key combinations, when we detect that the user is using a mac-style keyboard.
|
||||||
|
export function adjust_mac_kbd_tags(kbd_elem_class: string): void {
|
||||||
if (!has_mac_keyboard()) {
|
if (!has_mac_keyboard()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys_map = new Map([
|
|
||||||
["Backspace", "Delete"],
|
|
||||||
["Enter", "Return"],
|
|
||||||
["Home", "←"],
|
|
||||||
["End", "→"],
|
|
||||||
["PgUp", "↑"],
|
|
||||||
["PgDn", "↓"],
|
|
||||||
["Ctrl", "⌘"],
|
|
||||||
["Alt", "⌘"],
|
|
||||||
]);
|
|
||||||
|
|
||||||
const fn_shortcuts = new Set(["Home", "End", "PgUp", "PgDn"]);
|
|
||||||
|
|
||||||
$(kbd_elem_class).each(function () {
|
$(kbd_elem_class).each(function () {
|
||||||
let key_text = $(this).text();
|
let key_text = $(this).text();
|
||||||
|
|
||||||
|
@ -83,6 +85,26 @@ export function adjust_mac_shortcuts(kbd_elem_class: string): void {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We convert the hotkey hints used in the tooltips to mac equivalent
|
||||||
|
// key combinations, when we detect that the user is using a mac-style keyboard.
|
||||||
|
export function adjust_mac_tooltip_keys(hotkeys: string[]): void {
|
||||||
|
if (!has_mac_keyboard()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [index, hotkey] of hotkeys.entries()) {
|
||||||
|
const replace_key = keys_map.get(hotkey);
|
||||||
|
|
||||||
|
if (replace_key !== undefined) {
|
||||||
|
hotkeys[index] = replace_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fn_shortcuts.has(hotkey)) {
|
||||||
|
hotkeys.unshift("Fn");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// See https://zulip.readthedocs.io/en/latest/development/authentication.html#password-form-implementation
|
// See https://zulip.readthedocs.io/en/latest/development/authentication.html#password-form-implementation
|
||||||
// for design details on this feature.
|
// for design details on this feature.
|
||||||
function set_password_toggle_label(
|
function set_password_toggle_label(
|
||||||
|
|
|
@ -250,8 +250,8 @@ export function set_up_toggler() {
|
||||||
"notdisplayed",
|
"notdisplayed",
|
||||||
!user_settings.escape_navigates_to_default_view,
|
!user_settings.escape_navigates_to_default_view,
|
||||||
);
|
);
|
||||||
common.adjust_mac_shortcuts(".hotkeys_table .hotkey kbd");
|
common.adjust_mac_kbd_tags(".hotkeys_table .hotkey kbd");
|
||||||
common.adjust_mac_shortcuts("#markdown-instructions kbd");
|
common.adjust_mac_kbd_tags("#markdown-instructions kbd");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function show(target) {
|
export function show(target) {
|
||||||
|
|
|
@ -236,7 +236,7 @@ export function initialize() {
|
||||||
compose_enter_sends_popover_displayed = true;
|
compose_enter_sends_popover_displayed = true;
|
||||||
},
|
},
|
||||||
onMount(instance) {
|
onMount(instance) {
|
||||||
common.adjust_mac_shortcuts(".enter_sends_choices kbd");
|
common.adjust_mac_kbd_tags(".enter_sends_choices kbd");
|
||||||
|
|
||||||
$(instance.popper).one("click", ".enter_sends_choice", (e) => {
|
$(instance.popper).one("click", ".enter_sends_choice", (e) => {
|
||||||
let selected_behaviour = $(e.currentTarget)
|
let selected_behaviour = $(e.currentTarget)
|
||||||
|
|
|
@ -58,7 +58,7 @@ function render_code_sections() {
|
||||||
|
|
||||||
highlight_current_article();
|
highlight_current_article();
|
||||||
|
|
||||||
common.adjust_mac_shortcuts(".markdown kbd");
|
common.adjust_mac_kbd_tags(".markdown kbd");
|
||||||
|
|
||||||
$("table").each(function () {
|
$("table").each(function () {
|
||||||
$(this).addClass("table table-striped");
|
$(this).addClass("table table-striped");
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import Handlebars from "handlebars/runtime";
|
import Handlebars from "handlebars/runtime";
|
||||||
|
|
||||||
|
import * as common from "./common";
|
||||||
import {default_html_elements, intl} from "./i18n";
|
import {default_html_elements, intl} from "./i18n";
|
||||||
import * as util from "./util";
|
import * as util from "./util";
|
||||||
|
|
||||||
|
@ -108,6 +109,7 @@ Handlebars.registerHelper("numberFormat", (number) => number.toLocaleString());
|
||||||
Handlebars.registerHelper("hotkey_hints", (...hotkeys) => {
|
Handlebars.registerHelper("hotkey_hints", (...hotkeys) => {
|
||||||
hotkeys.pop(); // Handlebars options
|
hotkeys.pop(); // Handlebars options
|
||||||
let hotkey_hints = "";
|
let hotkey_hints = "";
|
||||||
|
common.adjust_mac_tooltip_keys(hotkeys);
|
||||||
for (const hotkey of hotkeys) {
|
for (const hotkey of hotkeys) {
|
||||||
hotkey_hints += `<span class="hotkey-hint">${hotkey}</span>`;
|
hotkey_hints += `<span class="hotkey-hint">${hotkey}</span>`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,7 +229,7 @@ function initialize_compose_box() {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
$(`.enter_sends_${user_settings.enter_sends}`).show();
|
$(`.enter_sends_${user_settings.enter_sends}`).show();
|
||||||
common.adjust_mac_shortcuts(".enter_sends kbd");
|
common.adjust_mac_kbd_tags(".enter_sends kbd");
|
||||||
}
|
}
|
||||||
|
|
||||||
function initialize_message_feed_errors() {
|
function initialize_message_feed_errors() {
|
||||||
|
|
Loading…
Reference in New Issue