compose: Move keydown and keyup from compose.js to compose_ui.js.

This commit moves the handle_keydown and handle_keydown functions
of compose.js to compose_ui.js.

Part of splitting compose.js.
This commit is contained in:
Priyam Seth
2021-07-28 21:53:34 +05:30
committed by Tim Abbott
parent de04f0ad67
commit 3ec55e7976
6 changed files with 265 additions and 260 deletions

View File

@@ -111,188 +111,6 @@ function initialize_handlers({override}) {
compose.initialize();
}
test_ui("right-to-left", () => {
const textarea = $("#compose-textarea");
const event = {
key: "A",
};
assert.equal(textarea.hasClass("rtl"), false);
textarea.val("```quote\nمرحبا");
compose.handle_keyup(event, $("#compose-textarea"));
assert.equal(textarea.hasClass("rtl"), true);
textarea.val("```quote foo");
compose.handle_keyup(event, textarea);
assert.equal(textarea.hasClass("rtl"), false);
});
test_ui("markdown_shortcuts", ({override}) => {
let queryCommandEnabled = true;
const event = {
key: "b",
target: {
id: "compose-textarea",
},
stopPropagation: noop,
preventDefault: noop,
};
let input_text = "";
let range_start = 0;
let range_length = 0;
let compose_value = $("#compose_textarea").val();
let selected_word = "";
override(document, "queryCommandEnabled", () => queryCommandEnabled);
override(document, "execCommand", (cmd, bool, markdown) => {
const compose_textarea = $("#compose-textarea");
const value = compose_textarea.val();
$("#compose-textarea").val(
value.slice(0, compose_textarea.range().start) +
markdown +
value.slice(compose_textarea.range().end),
);
});
$("#compose-textarea")[0] = {};
$("#compose-textarea").range = () => ({
start: range_start,
end: range_start + range_length,
length: range_length,
range: noop,
text: $("#compose-textarea")
.val()
.slice(range_start, range_length + range_start),
});
$("#compose-textarea").caret = noop;
function test_i_typed(isCtrl, isCmd) {
// Test 'i' is typed correctly.
$("#compose-textarea").val("i");
event.key = "i";
event.metaKey = isCmd;
event.ctrlKey = isCtrl;
compose.handle_keydown(event, $("#compose-textarea"));
assert.equal("i", $("#compose-textarea").val());
}
function all_markdown_test(isCtrl, isCmd) {
input_text = "Any text.";
$("#compose-textarea").val(input_text);
compose_value = $("#compose-textarea").val();
// Select "text" word in compose box.
selected_word = "text";
range_start = compose_value.search(selected_word);
range_length = selected_word.length;
// Test bold:
// Mac env = Cmd+b
// Windows/Linux = Ctrl+b
event.key = "b";
event.ctrlKey = isCtrl;
event.metaKey = isCmd;
compose.handle_keydown(event, $("#compose-textarea"));
assert.equal("Any **text**.", $("#compose-textarea").val());
// Test if no text is selected.
range_start = 0;
// Change cursor to first position.
range_length = 0;
compose.handle_keydown(event, $("#compose-textarea"));
assert.equal("****Any **text**.", $("#compose-textarea").val());
// Test italic:
// Mac = Cmd+I
// Windows/Linux = Ctrl+I
// We use event.key = "I" to emulate user using Caps Lock key.
$("#compose-textarea").val(input_text);
range_start = compose_value.search(selected_word);
range_length = selected_word.length;
event.key = "I";
event.shiftKey = false;
compose.handle_keydown(event, $("#compose-textarea"));
assert.equal("Any *text*.", $("#compose-textarea").val());
// Test if no text is selected.
range_length = 0;
// Change cursor to first position.
range_start = 0;
compose.handle_keydown(event, $("#compose-textarea"));
assert.equal("**Any *text*.", $("#compose-textarea").val());
// Test link insertion:
// Mac = Cmd+Shift+L
// Windows/Linux = Ctrl+Shift+L
$("#compose-textarea").val(input_text);
range_start = compose_value.search(selected_word);
range_length = selected_word.length;
event.key = "l";
event.shiftKey = true;
compose.handle_keydown(event, $("#compose-textarea"));
assert.equal("Any [text](url).", $("#compose-textarea").val());
// Test if exec command is not enabled in browser.
queryCommandEnabled = false;
compose.handle_keydown(event, $("#compose-textarea"));
}
// This function cross tests the Cmd/Ctrl + Markdown shortcuts in
// Mac and Linux/Windows environments. So in short, this tests
// that e.g. Cmd+B should be ignored on Linux/Windows and Ctrl+B
// should be ignored on Mac.
function os_specific_markdown_test(isCtrl, isCmd) {
input_text = "Any text.";
$("#compose-textarea").val(input_text);
compose_value = $("#compose-textarea").val();
selected_word = "text";
range_start = compose_value.search(selected_word);
range_length = selected_word.length;
event.metaKey = isCmd;
event.ctrlKey = isCtrl;
event.key = "b";
compose.handle_keydown(event, $("#compose-textarea"));
assert.equal(input_text, $("#compose-textarea").val());
event.key = "i";
event.shiftKey = false;
compose.handle_keydown(event, $("#compose-textarea"));
assert.equal(input_text, $("#compose-textarea").val());
event.key = "l";
event.shiftKey = true;
compose.handle_keydown(event, $("#compose-textarea"));
assert.equal(input_text, $("#compose-textarea").val());
}
// These keyboard shortcuts differ as to what key one should use
// on MacOS vs. other platforms: Cmd (Mac) vs. Ctrl (non-Mac).
// Default (Linux/Windows) userAgent tests:
navigator.platform = "";
test_i_typed(false, false);
// Check all the Ctrl + Markdown shortcuts work correctly
all_markdown_test(true, false);
// The Cmd + Markdown shortcuts should do nothing on Linux/Windows
os_specific_markdown_test(false, true);
// Setting following platform to test in mac env
navigator.platform = "MacIntel";
// Mac userAgent tests:
test_i_typed(false, false);
// The Ctrl + Markdown shortcuts should do nothing on mac
os_specific_markdown_test(true, false);
// Check all the Cmd + Markdown shortcuts work correctly
all_markdown_test(false, true);
// Reset userAgent
navigator.userAgent = "";
});
test_ui("send_message_success", ({override}) => {
override(drafts, "delete_active_draft", () => {});

View File

@@ -9,11 +9,14 @@ const {mock_esm, set_global, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery");
const noop = () => {};
set_global("document", {
execCommand() {
return false;
},
});
set_global("navigator", {});
mock_esm("../../static/js/message_lists", {
current: {},
@@ -456,3 +459,185 @@ run_test("test_compose_height_changes", ({override}) => {
assert.ok(!compose_ui.is_full_size());
assert.ok(!compose_box_top_set);
});
run_test("markdown_shortcuts", ({override}) => {
let queryCommandEnabled = true;
const event = {
key: "b",
target: {
id: "compose-textarea",
},
stopPropagation: noop,
preventDefault: noop,
};
let input_text = "";
let range_start = 0;
let range_length = 0;
let compose_value = $("#compose_textarea").val();
let selected_word = "";
override(document, "queryCommandEnabled", () => queryCommandEnabled);
override(document, "execCommand", (cmd, bool, markdown) => {
const compose_textarea = $("#compose-textarea");
const value = compose_textarea.val();
$("#compose-textarea").val(
value.slice(0, compose_textarea.range().start) +
markdown +
value.slice(compose_textarea.range().end),
);
});
$("#compose-textarea")[0] = {};
$("#compose-textarea").range = () => ({
start: range_start,
end: range_start + range_length,
length: range_length,
range: noop,
text: $("#compose-textarea")
.val()
.slice(range_start, range_length + range_start),
});
$("#compose-textarea").caret = noop;
function test_i_typed(isCtrl, isCmd) {
// Test 'i' is typed correctly.
$("#compose-textarea").val("i");
event.key = "i";
event.metaKey = isCmd;
event.ctrlKey = isCtrl;
compose_ui.handle_keydown(event, $("#compose-textarea"));
assert.equal("i", $("#compose-textarea").val());
}
function all_markdown_test(isCtrl, isCmd) {
input_text = "Any text.";
$("#compose-textarea").val(input_text);
compose_value = $("#compose-textarea").val();
// Select "text" word in compose box.
selected_word = "text";
range_start = compose_value.search(selected_word);
range_length = selected_word.length;
// Test bold:
// Mac env = Cmd+b
// Windows/Linux = Ctrl+b
event.key = "b";
event.ctrlKey = isCtrl;
event.metaKey = isCmd;
compose_ui.handle_keydown(event, $("#compose-textarea"));
assert.equal("Any **text**.", $("#compose-textarea").val());
// Test if no text is selected.
range_start = 0;
// Change cursor to first position.
range_length = 0;
compose_ui.handle_keydown(event, $("#compose-textarea"));
assert.equal("****Any **text**.", $("#compose-textarea").val());
// Test italic:
// Mac = Cmd+I
// Windows/Linux = Ctrl+I
// We use event.key = "I" to emulate user using Caps Lock key.
$("#compose-textarea").val(input_text);
range_start = compose_value.search(selected_word);
range_length = selected_word.length;
event.key = "I";
event.shiftKey = false;
compose_ui.handle_keydown(event, $("#compose-textarea"));
assert.equal("Any *text*.", $("#compose-textarea").val());
// Test if no text is selected.
range_length = 0;
// Change cursor to first position.
range_start = 0;
compose_ui.handle_keydown(event, $("#compose-textarea"));
assert.equal("**Any *text*.", $("#compose-textarea").val());
// Test link insertion:
// Mac = Cmd+Shift+L
// Windows/Linux = Ctrl+Shift+L
$("#compose-textarea").val(input_text);
range_start = compose_value.search(selected_word);
range_length = selected_word.length;
event.key = "l";
event.shiftKey = true;
compose_ui.handle_keydown(event, $("#compose-textarea"));
assert.equal("Any [text](url).", $("#compose-textarea").val());
// Test if exec command is not enabled in browser.
queryCommandEnabled = false;
compose_ui.handle_keydown(event, $("#compose-textarea"));
}
// This function cross tests the Cmd/Ctrl + Markdown shortcuts in
// Mac and Linux/Windows environments. So in short, this tests
// that e.g. Cmd+B should be ignored on Linux/Windows and Ctrl+B
// should be ignored on Mac.
function os_specific_markdown_test(isCtrl, isCmd) {
input_text = "Any text.";
$("#compose-textarea").val(input_text);
compose_value = $("#compose-textarea").val();
selected_word = "text";
range_start = compose_value.search(selected_word);
range_length = selected_word.length;
event.metaKey = isCmd;
event.ctrlKey = isCtrl;
event.key = "b";
compose_ui.handle_keydown(event, $("#compose-textarea"));
assert.equal(input_text, $("#compose-textarea").val());
event.key = "i";
event.shiftKey = false;
compose_ui.handle_keydown(event, $("#compose-textarea"));
assert.equal(input_text, $("#compose-textarea").val());
event.key = "l";
event.shiftKey = true;
compose_ui.handle_keydown(event, $("#compose-textarea"));
assert.equal(input_text, $("#compose-textarea").val());
}
// These keyboard shortcuts differ as to what key one should use
// on MacOS vs. other platforms: Cmd (Mac) vs. Ctrl (non-Mac).
// Default (Linux/Windows) userAgent tests:
navigator.platform = "";
test_i_typed(false, false);
// Check all the Ctrl + Markdown shortcuts work correctly
all_markdown_test(true, false);
// The Cmd + Markdown shortcuts should do nothing on Linux/Windows
os_specific_markdown_test(false, true);
// Setting following platform to test in mac env
navigator.platform = "MacIntel";
// Mac userAgent tests:
test_i_typed(false, false);
// The Ctrl + Markdown shortcuts should do nothing on mac
os_specific_markdown_test(true, false);
// Check all the Cmd + Markdown shortcuts work correctly
all_markdown_test(false, true);
// Reset userAgent
navigator.userAgent = "";
});
run_test("right-to-left", () => {
const textarea = $("#compose-textarea");
const event = {
key: "A",
};
assert.equal(textarea.hasClass("rtl"), false);
textarea.val("```quote\nمرحبا");
compose_ui.handle_keyup(event, $("#compose-textarea"));
assert.equal(textarea.hasClass("rtl"), true);
textarea.val("```quote foo");
compose_ui.handle_keyup(event, textarea);
assert.equal(textarea.hasClass("rtl"), false);
});

View File

@@ -7,7 +7,6 @@ import render_compose_private_stream_alert from "../templates/compose_private_st
import * as blueslip from "./blueslip";
import * as channel from "./channel";
import * as common from "./common";
import * as compose_actions from "./compose_actions";
import * as compose_error from "./compose_error";
import * as compose_fade from "./compose_fade";
@@ -28,7 +27,6 @@ import * as reminder from "./reminder";
import * as rendered_markdown from "./rendered_markdown";
import * as resize from "./resize";
import * as rows from "./rows";
import * as rtl from "./rtl";
import * as sent_messages from "./sent_messages";
import * as server_events from "./server_events";
import * as settings_data from "./settings_data";
@@ -337,77 +335,6 @@ export function update_email(user_id, new_email) {
compose_state.private_message_recipient(reply_to);
}
export function handle_keydown(event, textarea) {
// The event.key property will have uppercase letter if
// the "Shift + <key>" combo was used or the Caps Lock
// key was on. We turn to key to lowercase so the keybindings
// work regardless of whether Caps Lock was on or not.
const key = event.key.toLowerCase();
const isBold = key === "b";
const isItalic = key === "i" && !event.shiftKey;
const isLink = key === "l" && event.shiftKey;
// detect Cmd and Ctrl key
const isCmdOrCtrl = common.has_mac_keyboard() ? event.metaKey : event.ctrlKey;
if ((isBold || isItalic || isLink) && isCmdOrCtrl) {
const range = textarea.range();
if (isBold) {
// Ctrl + B: Convert selected text to bold text
compose_ui.wrap_text_with_markdown(textarea, "**", "**");
event.preventDefault();
if (!range.length) {
textarea.caret(textarea.caret() - 2);
}
}
if (isItalic) {
// Ctrl + I: Convert selected text to italic text
compose_ui.wrap_text_with_markdown(textarea, "*", "*");
event.preventDefault();
if (!range.length) {
textarea.caret(textarea.caret() - 1);
}
}
if (isLink) {
// Ctrl + L: Insert a link to selected text
compose_ui.wrap_text_with_markdown(textarea, "[", "](url)");
event.preventDefault();
const position = textarea.caret();
const txt = textarea[0];
// Include selected text in between [] parentheses and insert '(url)'
// where "url" should be automatically selected.
// Position of cursor depends on whether browser supports exec
// command or not. So set cursor position accordingly.
if (range.length > 0) {
if (document.queryCommandEnabled("insertText")) {
txt.selectionStart = position - 4;
txt.selectionEnd = position - 1;
} else {
txt.selectionStart = position + range.length + 3;
txt.selectionEnd = position + range.length + 6;
}
} else {
textarea.caret(textarea.caret() - 6);
}
}
compose_ui.autosize_textarea(textarea);
return;
}
}
export function handle_keyup(event, textarea) {
// Set the rtl class if the text has an rtl direction, remove it otherwise
rtl.set_rtl_class_for_textarea(textarea);
}
export function needs_subscribe_warning(user_id, stream_id) {
// This returns true if all of these conditions are met:
// * the user is valid
@@ -630,10 +557,10 @@ export function initialize() {
"#stream_message_recipient_stream,#stream_message_recipient_topic,#private_message_recipient",
).on("change", update_fade);
$("#compose-textarea").on("keydown", (event) => {
handle_keydown(event, $("#compose-textarea").expectOne());
compose_ui.handle_keydown(event, $("#compose-textarea").expectOne());
});
$("#compose-textarea").on("keyup", (event) => {
handle_keyup(event, $("#compose-textarea").expectOne());
compose_ui.handle_keyup(event, $("#compose-textarea").expectOne());
});
$("#compose-textarea").on("input propertychange", () => {

View File

@@ -1,8 +1,10 @@
import autosize from "autosize";
import $ from "jquery";
import * as common from "./common";
import {$t} from "./i18n";
import * as people from "./people";
import * as rtl from "./rtl";
import * as user_status from "./user_status";
let full_size_status = false; // true or false
@@ -194,3 +196,74 @@ export function make_compose_box_original_size() {
$(".expand_composebox_button").show();
$("#compose-textarea").trigger("focus");
}
export function handle_keydown(event, textarea) {
// The event.key property will have uppercase letter if
// the "Shift + <key>" combo was used or the Caps Lock
// key was on. We turn to key to lowercase so the keybindings
// work regardless of whether Caps Lock was on or not.
const key = event.key.toLowerCase();
const isBold = key === "b";
const isItalic = key === "i" && !event.shiftKey;
const isLink = key === "l" && event.shiftKey;
// detect Cmd and Ctrl key
const isCmdOrCtrl = common.has_mac_keyboard() ? event.metaKey : event.ctrlKey;
if ((isBold || isItalic || isLink) && isCmdOrCtrl) {
const range = textarea.range();
if (isBold) {
// Ctrl + B: Convert selected text to bold text
wrap_text_with_markdown(textarea, "**", "**");
event.preventDefault();
if (!range.length) {
textarea.caret(textarea.caret() - 2);
}
}
if (isItalic) {
// Ctrl + I: Convert selected text to italic text
wrap_text_with_markdown(textarea, "*", "*");
event.preventDefault();
if (!range.length) {
textarea.caret(textarea.caret() - 1);
}
}
if (isLink) {
// Ctrl + L: Insert a link to selected text
wrap_text_with_markdown(textarea, "[", "](url)");
event.preventDefault();
const position = textarea.caret();
const txt = textarea[0];
// Include selected text in between [] parentheses and insert '(url)'
// where "url" should be automatically selected.
// Position of cursor depends on whether browser supports exec
// command or not. So set cursor position accordingly.
if (range.length > 0) {
if (document.queryCommandEnabled("insertText")) {
txt.selectionStart = position - 4;
txt.selectionEnd = position - 1;
} else {
txt.selectionStart = position + range.length + 3;
txt.selectionEnd = position + range.length + 6;
}
} else {
textarea.caret(textarea.caret() - 6);
}
}
autosize_textarea(textarea);
return;
}
}
export function handle_keyup(event, textarea) {
// Set the rtl class if the text has an rtl direction, remove it otherwise
rtl.set_rtl_class_for_textarea(textarea);
}

View File

@@ -10,6 +10,7 @@ import * as blueslip from "./blueslip";
import * as channel from "./channel";
import * as compose from "./compose";
import * as compose_actions from "./compose_actions";
import * as compose_ui from "./compose_ui";
import * as composebox_typeahead from "./composebox_typeahead";
import * as condense from "./condense";
import * as confirm_dialog from "./confirm_dialog";
@@ -473,12 +474,12 @@ function edit_message(row, raw_content) {
currently_editing_messages.get(rows.id(row)).listeners = listeners;
}
composebox_typeahead.initialize_compose_typeahead(edit_id);
compose.handle_keyup(null, $(edit_id).expectOne());
compose_ui.handle_keyup(null, $(edit_id).expectOne());
$(edit_id).on("keydown", function (event) {
compose.handle_keydown(event, $(this).expectOne());
compose_ui.handle_keydown(event, $(this).expectOne());
});
$(edit_id).on("keyup", function (event) {
compose.handle_keyup(event, $(this).expectOne());
compose_ui.handle_keyup(event, $(this).expectOne());
});
break;
}

View File

@@ -52,6 +52,7 @@ EXEMPT_FILES = {
"static/js/compose_fade.js",
"static/js/compose_validate.js",
"static/js/compose.js",
"static/js/compose_ui.js",
"static/js/condense.js",
"static/js/confirm_dialog.js",
"static/js/dialog_widget.js",