DEV: Normalize key modifier checks for keyboard shortcuts (#22451)

This introduces a PLATFORM_KEY_MODIFIER const that
can be used both client and server side, to determine
whether we should be using the Meta or Ctrl key based
on whether the user is on Windows/Linux or Mac.
This commit is contained in:
Martin Brennan
2023-07-06 13:34:24 +10:00
committed by GitHub
parent 4c810703c1
commit 1cd512a03a
9 changed files with 57 additions and 53 deletions

View File

@ -1,4 +1,5 @@
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { PLATFORM_KEY_MODIFIER } from "discourse/lib/keyboard-shortcuts";
import { import {
caretPosition, caretPosition,
inCodeBlock, inCodeBlock,
@ -180,15 +181,14 @@ class Toolbar {
const title = I18n.t(button.title || `composer.${button.id}_title`); const title = I18n.t(button.title || `composer.${button.id}_title`);
if (button.shortcut) { if (button.shortcut) {
const mac = /Mac|iPod|iPhone|iPad/.test(navigator.platform); const shortcutTitle = `${translateModKey(
const mod = mac ? "Meta" : "Ctrl"; PLATFORM_KEY_MODIFIER + "+"
)}${translateModKey(button.shortcut)}`;
const shortcutTitle = `${translateModKey(mod + "+")}${translateModKey(
button.shortcut
)}`;
createdButton.title = `${title} (${shortcutTitle})`; createdButton.title = `${title} (${shortcutTitle})`;
this.shortcuts[`${mod}+${button.shortcut}`.toLowerCase()] = createdButton; this.shortcuts[
`${PLATFORM_KEY_MODIFIER}+${button.shortcut}`.toLowerCase()
] = createdButton;
} else { } else {
createdButton.title = title; createdButton.title = title;
} }
@ -304,11 +304,9 @@ export default Component.extend(TextareaTextManipulation, {
this._itsatrap.bind("tab", () => this.indentSelection("right")); this._itsatrap.bind("tab", () => this.indentSelection("right"));
this._itsatrap.bind("shift+tab", () => this.indentSelection("left")); this._itsatrap.bind("shift+tab", () => this.indentSelection("left"));
this._itsatrap.bind(`${PLATFORM_KEY_MODIFIER}+shift+.`, () =>
const mac = /Mac|iPod|iPhone|iPad/.test(navigator.platform); this.send("insertCurrentTime")
const mod = mac ? "meta" : "ctrl"; );
this._itsatrap.bind(`${mod}+shift+.`, () => this.send("insertCurrentTime"));
// disable clicking on links in the preview // disable clicking on links in the preview
this.element this.element

View File

@ -33,6 +33,12 @@ export function clearExtraKeyboardShortcutHelp() {
export { extraKeyboardShortcutsHelp as extraKeyboardShortcutsHelp }; export { extraKeyboardShortcutsHelp as extraKeyboardShortcutsHelp };
export const PLATFORM_KEY_MODIFIER = /Mac|iPod|iPhone|iPad/.test(
navigator.platform
)
? "meta"
: "ctrl";
const DEFAULT_BINDINGS = { const DEFAULT_BINDINGS = {
"!": { postAction: "showFlags" }, "!": { postAction: "showFlags" },
"#": { handler: "goToPost", anonymous: true }, "#": { handler: "goToPost", anonymous: true },

View File

@ -520,16 +520,18 @@ export function translateModKey(string) {
// Apple device users are used to glyphs for shortcut keys // Apple device users are used to glyphs for shortcut keys
if (isApple) { if (isApple) {
string = string string = string
.replace("Shift", "\u21E7") .toLowerCase()
.replace("Meta", "\u2318") .replace("shift", "\u21E7")
.replace("Alt", "\u2325") .replace("meta", "\u2318")
.replace("alt", "\u2325")
.replace(/\+/g, ""); .replace(/\+/g, "");
} else { } else {
string = string string = string
.replace("Shift", I18n.t("shortcut_modifier_key.shift")) .toLowerCase()
.replace("Ctrl", I18n.t("shortcut_modifier_key.ctrl")) .replace("shift", I18n.t("shortcut_modifier_key.shift"))
.replace("Meta", I18n.t("shortcut_modifier_key.ctrl")) .replace("ctrl", I18n.t("shortcut_modifier_key.ctrl"))
.replace("Alt", I18n.t("shortcut_modifier_key.alt")); .replace("meta", I18n.t("shortcut_modifier_key.ctrl"))
.replace("alt", I18n.t("shortcut_modifier_key.alt"));
} }
return string; return string;

View File

@ -7,6 +7,7 @@ import {
triggerKeyEvent, triggerKeyEvent,
visit, visit,
} from "@ember/test-helpers"; } from "@ember/test-helpers";
import { PLATFORM_KEY_MODIFIER } from "discourse/lib/keyboard-shortcuts";
import { toggleCheckDraftPopup } from "discourse/services/composer"; import { toggleCheckDraftPopup } from "discourse/services/composer";
import { cloneJSON } from "discourse-common/lib/object"; import { cloneJSON } from "discourse-common/lib/object";
import TopicFixtures from "discourse/tests/fixtures/topic"; import TopicFixtures from "discourse/tests/fixtures/topic";
@ -217,10 +218,9 @@ acceptance("Composer", function (needs) {
textarea.selectionEnd = textarea.value.length; textarea.selectionEnd = textarea.value.length;
// Testing keyboard events is tough! // Testing keyboard events is tough!
const mac = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
const event = document.createEvent("Event"); const event = document.createEvent("Event");
event.initEvent("keydown", true, true); event.initEvent("keydown", true, true);
event[mac ? "metaKey" : "ctrlKey"] = true; event[`${PLATFORM_KEY_MODIFIER}Key`] = true;
event.key = "B"; event.key = "B";
event.keyCode = 66; event.keyCode = 66;
@ -1371,14 +1371,14 @@ acceptance("Composer - current time", function (needs) {
assert.ok(exists(".d-editor-input"), "the composer input is visible"); assert.ok(exists(".d-editor-input"), "the composer input is visible");
await fillIn(".d-editor-input", "and the time now is: "); await fillIn(".d-editor-input", "and the time now is: ");
const mac = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
const date = moment().format("YYYY-MM-DD"); const date = moment().format("YYYY-MM-DD");
await triggerKeyEvent(".d-editor-input", "keydown", ".", { const eventOptions = {
shiftKey: true, shiftKey: true,
ctrlKey: !mac, };
metaKey: mac, eventOptions[`${PLATFORM_KEY_MODIFIER}Key`] = true;
});
await triggerKeyEvent(".d-editor-input", "keydown", ".", eventOptions);
const inputValue = query("#reply-control .d-editor-input").value.trim(); const inputValue = query("#reply-control .d-editor-input").value.trim();

View File

@ -1,10 +1,7 @@
import { withPluginApi } from "discourse/lib/plugin-api"; import { withPluginApi } from "discourse/lib/plugin-api";
import { PLATFORM_KEY_MODIFIER } from "discourse/lib/keyboard-shortcuts";
import ChatNewMessageModal from "discourse/plugins/chat/discourse/components/modal/chat-new-message"; import ChatNewMessageModal from "discourse/plugins/chat/discourse/components/modal/chat-new-message";
const APPLE =
navigator.platform.startsWith("Mac") || navigator.platform === "iPhone";
export const KEY_MODIFIER = APPLE ? "meta" : "ctrl";
export default { export default {
name: "chat-keyboard-shortcuts", name: "chat-keyboard-shortcuts",
@ -127,17 +124,21 @@ export default {
}; };
withPluginApi("0.12.1", (api) => { withPluginApi("0.12.1", (api) => {
api.addKeyboardShortcut(`${KEY_MODIFIER}+k`, openChannelSelector, { api.addKeyboardShortcut(
global: true, `${PLATFORM_KEY_MODIFIER}+k`,
help: { openChannelSelector,
category: "chat", {
name: "chat.keyboard_shortcuts.open_quick_channel_selector", global: true,
definition: { help: {
keys1: ["meta", "k"], category: "chat",
keysDelimiter: "plus", name: "chat.keyboard_shortcuts.open_quick_channel_selector",
definition: {
keys1: ["meta", "k"],
keysDelimiter: "plus",
},
}, },
}, }
}); );
api.addKeyboardShortcut("alt+up", handleMoveUpShortcut, { api.addKeyboardShortcut("alt+up", handleMoveUpShortcut, {
global: true, global: true,
help: { help: {
@ -156,7 +157,7 @@ export default {
global: true, global: true,
}); });
api.addKeyboardShortcut( api.addKeyboardShortcut(
`${KEY_MODIFIER}+b`, `${PLATFORM_KEY_MODIFIER}+b`,
(event) => modifyComposerSelection(event, "bold"), (event) => modifyComposerSelection(event, "bold"),
{ {
global: true, global: true,
@ -171,7 +172,7 @@ export default {
} }
); );
api.addKeyboardShortcut( api.addKeyboardShortcut(
`${KEY_MODIFIER}+i`, `${PLATFORM_KEY_MODIFIER}+i`,
(event) => modifyComposerSelection(event, "italic"), (event) => modifyComposerSelection(event, "italic"),
{ {
global: true, global: true,
@ -186,7 +187,7 @@ export default {
} }
); );
api.addKeyboardShortcut( api.addKeyboardShortcut(
`${KEY_MODIFIER}+e`, `${PLATFORM_KEY_MODIFIER}+e`,
(event) => modifyComposerSelection(event, "code"), (event) => modifyComposerSelection(event, "code"),
{ {
global: true, global: true,
@ -201,7 +202,7 @@ export default {
} }
); );
api.addKeyboardShortcut( api.addKeyboardShortcut(
`${KEY_MODIFIER}+l`, `${PLATFORM_KEY_MODIFIER}+l`,
(event) => openInsertLinkModal(event), (event) => openInsertLinkModal(event),
{ {
global: true, global: true,

View File

@ -7,7 +7,6 @@ RSpec.describe "Chat | composer | shortcuts | channel", type: :system do
let(:chat) { PageObjects::Pages::Chat.new } let(:chat) { PageObjects::Pages::Chat.new }
let(:channel_page) { PageObjects::Pages::ChatChannel.new } let(:channel_page) { PageObjects::Pages::ChatChannel.new }
let(:thread_page) { PageObjects::Pages::ChatThread.new } let(:thread_page) { PageObjects::Pages::ChatThread.new }
let(:key_modifier) { RUBY_PLATFORM =~ /darwin/i ? :meta : :control }
before do before do
chat_system_bootstrap chat_system_bootstrap

View File

@ -3,8 +3,6 @@
module PageObjects module PageObjects
module Pages module Pages
class Chat < PageObjects::Pages::Base class Chat < PageObjects::Pages::Base
MODIFIER = RUBY_PLATFORM =~ /darwin/i ? :meta : :control
def message_creator def message_creator
@message_creator ||= PageObjects::Components::Chat::MessageCreator.new @message_creator ||= PageObjects::Components::Chat::MessageCreator.new
end end
@ -24,7 +22,7 @@ module PageObjects
end end
def open_new_message def open_new_message
send_keys([MODIFIER, "k"]) send_keys([PLATFORM_KEY_MODIFIER, "k"])
find(".chat-new-message-modal") find(".chat-new-message-modal")
end end

View File

@ -8,8 +8,6 @@ module PageObjects
SELECTOR = ".chat-composer__wrapper" SELECTOR = ".chat-composer__wrapper"
MODIFIER = RUBY_PLATFORM =~ /darwin/i ? :meta : :control
def initialize(context) def initialize(context)
@context = context @context = context
end end
@ -59,7 +57,7 @@ module PageObjects
end end
def emphasized_text_shortcut def emphasized_text_shortcut
input.send_keys([MODIFIER, "i"]) input.send_keys([PLATFORM_KEY_MODIFIER, "i"])
end end
def cancel_shortcut def cancel_shortcut
@ -67,11 +65,11 @@ module PageObjects
end end
def indented_text_shortcut def indented_text_shortcut
input.send_keys([MODIFIER, "e"]) input.send_keys([PLATFORM_KEY_MODIFIER, "e"])
end end
def bold_text_shortcut def bold_text_shortcut
input.send_keys([MODIFIER, "b"]) input.send_keys([PLATFORM_KEY_MODIFIER, "b"])
end end
def open_emoji_picker def open_emoji_picker

View File

@ -2,6 +2,8 @@
require "highline/import" require "highline/import"
module SystemHelpers module SystemHelpers
PLATFORM_KEY_MODIFIER = RUBY_PLATFORM =~ /darwin/i ? :meta : :control
def pause_test def pause_test
result = result =
ask( ask(