mirror of https://github.com/zulip/zulip.git
compose: Change UI which toggles `enter_sends` setting.
Use a popover which displays both the options instead of long text. We only use a small text indicating the current state which user can click on to trigger the popover.
This commit is contained in:
parent
937d49e209
commit
db09639f6c
|
@ -9,7 +9,6 @@ const {page_params, user_settings} = require("../zjsunit/zpage_params");
|
||||||
|
|
||||||
const noop = () => {};
|
const noop = () => {};
|
||||||
|
|
||||||
const channel = mock_esm("../../static/js/channel");
|
|
||||||
const compose = mock_esm("../../static/js/compose", {
|
const compose = mock_esm("../../static/js/compose", {
|
||||||
finish: noop,
|
finish: noop,
|
||||||
});
|
});
|
||||||
|
@ -1142,32 +1141,11 @@ test("initialize", ({override, mock_template}) => {
|
||||||
event.key = "a";
|
event.key = "a";
|
||||||
$("form#send_message_form").trigger(event);
|
$("form#send_message_form").trigger(event);
|
||||||
|
|
||||||
// select_on_focus()
|
|
||||||
|
|
||||||
let channel_patch_called = false;
|
|
||||||
override(channel, "patch", (params) => {
|
|
||||||
assert.equal(params.url, "/json/settings");
|
|
||||||
assert.equal(params.idempotent, true);
|
|
||||||
assert.deepEqual(params.data, {enter_sends: user_settings.enter_sends});
|
|
||||||
|
|
||||||
channel_patch_called = true;
|
|
||||||
});
|
|
||||||
user_settings.enter_sends = false;
|
|
||||||
$(".enter_sends").trigger("click");
|
|
||||||
assert.equal(user_settings.enter_sends, true);
|
|
||||||
|
|
||||||
// Now we re-run both .initialize() and the click handler, this time
|
|
||||||
// with enter_sends: user_settings.enter_sends being true
|
|
||||||
user_settings.enter_sends = true;
|
|
||||||
$(".enter_sends").trigger("click");
|
|
||||||
assert.equal(user_settings.enter_sends, false);
|
|
||||||
|
|
||||||
$("#stream_message_recipient_stream").off("focus");
|
$("#stream_message_recipient_stream").off("focus");
|
||||||
$("#stream_message_recipient_topic").off("focus");
|
$("#stream_message_recipient_topic").off("focus");
|
||||||
$("#private_message_recipient").off("focus");
|
$("#private_message_recipient").off("focus");
|
||||||
$("form#send_message_form").off("keydown");
|
$("form#send_message_form").off("keydown");
|
||||||
$("form#send_message_form").off("keyup");
|
$("form#send_message_form").off("keyup");
|
||||||
$(".enter_sends").off("click");
|
|
||||||
$("#private_message_recipient").off("blur");
|
$("#private_message_recipient").off("blur");
|
||||||
ct.initialize();
|
ct.initialize();
|
||||||
|
|
||||||
|
@ -1176,7 +1154,6 @@ test("initialize", ({override, mock_template}) => {
|
||||||
assert.ok(stream_typeahead_called);
|
assert.ok(stream_typeahead_called);
|
||||||
assert.ok(subject_typeahead_called);
|
assert.ok(subject_typeahead_called);
|
||||||
assert.ok(pm_recipient_typeahead_called);
|
assert.ok(pm_recipient_typeahead_called);
|
||||||
assert.ok(channel_patch_called);
|
|
||||||
assert.ok(compose_textarea_typeahead_called);
|
assert.ok(compose_textarea_typeahead_called);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -265,12 +265,18 @@ class CommonUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
async ensure_enter_does_not_send(page: Page): Promise<void> {
|
async ensure_enter_does_not_send(page: Page): Promise<void> {
|
||||||
|
let enter_sends = false;
|
||||||
await page.$eval(".enter_sends_false", (el) => {
|
await page.$eval(".enter_sends_false", (el) => {
|
||||||
if ((el as HTMLElement).style.display !== "none") {
|
if ((el as HTMLElement).style.display !== "none") {
|
||||||
// Click events gets propagated to `.enter_sends` which toggles the value.
|
enter_sends = true;
|
||||||
(el as HTMLElement).click();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (enter_sends) {
|
||||||
|
const enter_sends_false_selector = ".enter_sends_choice input[value='false']";
|
||||||
|
await page.waitForSelector(enter_sends_false_selector);
|
||||||
|
await page.click(enter_sends_false_selector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async assert_compose_box_content(page: Page, expected_value: string): Promise<void> {
|
async assert_compose_box_content(page: Page, expected_value: string): Promise<void> {
|
||||||
|
|
|
@ -660,6 +660,11 @@ export function initialize() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($(".enter_sends").has(e.target).length) {
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Don't let clicks in the compose area count as
|
// Don't let clicks in the compose area count as
|
||||||
// "unfocusing" our compose -- in other words, e.g.
|
// "unfocusing" our compose -- in other words, e.g.
|
||||||
// clicking "Press Enter to send" should not
|
// clicking "Press Enter to send" should not
|
||||||
|
@ -872,6 +877,7 @@ export function initialize() {
|
||||||
!$(e.target).closest(".micromodal").length &&
|
!$(e.target).closest(".micromodal").length &&
|
||||||
!$(e.target).closest("[data-tippy-root]").length &&
|
!$(e.target).closest("[data-tippy-root]").length &&
|
||||||
!$(e.target).closest(".modal-backdrop").length &&
|
!$(e.target).closest(".modal-backdrop").length &&
|
||||||
|
!$(e.target).closest(".enter_sends").length &&
|
||||||
$(e.target).closest("body").length
|
$(e.target).closest("body").length
|
||||||
) {
|
) {
|
||||||
// Unfocus our compose area if we click out of it. Don't let exits out
|
// Unfocus our compose area if we click out of it. Don't let exits out
|
||||||
|
|
|
@ -7,7 +7,6 @@ import pygments_data from "../generated/pygments_data.json";
|
||||||
import * as emoji from "../shared/js/emoji";
|
import * as emoji from "../shared/js/emoji";
|
||||||
import * as typeahead from "../shared/js/typeahead";
|
import * as typeahead from "../shared/js/typeahead";
|
||||||
|
|
||||||
import * as channel from "./channel";
|
|
||||||
import * as compose from "./compose";
|
import * as compose from "./compose";
|
||||||
import * as compose_pm_pill from "./compose_pm_pill";
|
import * as compose_pm_pill from "./compose_pm_pill";
|
||||||
import * as compose_state from "./compose_state";
|
import * as compose_state from "./compose_state";
|
||||||
|
@ -1177,22 +1176,6 @@ export function initialize() {
|
||||||
$("form#send_message_form").on("keydown", handle_keydown);
|
$("form#send_message_form").on("keydown", handle_keydown);
|
||||||
$("form#send_message_form").on("keyup", handle_keyup);
|
$("form#send_message_form").on("keyup", handle_keyup);
|
||||||
|
|
||||||
$(".enter_sends").on("click", () => {
|
|
||||||
user_settings.enter_sends = !user_settings.enter_sends;
|
|
||||||
$(`.enter_sends_${!user_settings.enter_sends}`).hide();
|
|
||||||
$(`.enter_sends_${user_settings.enter_sends}`).show();
|
|
||||||
|
|
||||||
// Refocus in the content box so you can continue typing or
|
|
||||||
// press Enter to send.
|
|
||||||
$("#compose-textarea").trigger("focus");
|
|
||||||
|
|
||||||
return channel.patch({
|
|
||||||
url: "/json/settings",
|
|
||||||
idempotent: true,
|
|
||||||
data: {enter_sends: user_settings.enter_sends},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// limit number of items so the list doesn't fall off the screen
|
// limit number of items so the list doesn't fall off the screen
|
||||||
$("#stream_message_recipient_stream").typeahead({
|
$("#stream_message_recipient_stream").typeahead({
|
||||||
source() {
|
source() {
|
||||||
|
|
|
@ -6,17 +6,22 @@ import $ from "jquery";
|
||||||
import {delegate} from "tippy.js";
|
import {delegate} from "tippy.js";
|
||||||
|
|
||||||
import render_compose_control_buttons_popover from "../templates/compose_control_buttons_popover.hbs";
|
import render_compose_control_buttons_popover from "../templates/compose_control_buttons_popover.hbs";
|
||||||
|
import render_compose_select_enter_behaviour_popover from "../templates/compose_select_enter_behaviour_popover.hbs";
|
||||||
import render_left_sidebar_stream_setting_popover from "../templates/left_sidebar_stream_setting_popover.hbs";
|
import render_left_sidebar_stream_setting_popover from "../templates/left_sidebar_stream_setting_popover.hbs";
|
||||||
import render_mobile_message_buttons_popover_content from "../templates/mobile_message_buttons_popover_content.hbs";
|
import render_mobile_message_buttons_popover_content from "../templates/mobile_message_buttons_popover_content.hbs";
|
||||||
|
|
||||||
|
import * as channel from "./channel";
|
||||||
|
import * as common from "./common";
|
||||||
import * as compose_actions from "./compose_actions";
|
import * as compose_actions from "./compose_actions";
|
||||||
import * as giphy from "./giphy";
|
import * as giphy from "./giphy";
|
||||||
import * as narrow_state from "./narrow_state";
|
import * as narrow_state from "./narrow_state";
|
||||||
import * as popovers from "./popovers";
|
import * as popovers from "./popovers";
|
||||||
import * as settings_data from "./settings_data";
|
import * as settings_data from "./settings_data";
|
||||||
|
import {user_settings} from "./user_settings";
|
||||||
|
|
||||||
let left_sidebar_stream_setting_popover_displayed = false;
|
let left_sidebar_stream_setting_popover_displayed = false;
|
||||||
let compose_mobile_button_popover_displayed = false;
|
let compose_mobile_button_popover_displayed = false;
|
||||||
|
export let compose_enter_sends_popover_displayed = false;
|
||||||
let compose_control_buttons_popover_instance;
|
let compose_control_buttons_popover_instance;
|
||||||
|
|
||||||
export function get_compose_control_buttons_popover() {
|
export function get_compose_control_buttons_popover() {
|
||||||
|
@ -41,7 +46,8 @@ export function any_active() {
|
||||||
return (
|
return (
|
||||||
left_sidebar_stream_setting_popover_displayed ||
|
left_sidebar_stream_setting_popover_displayed ||
|
||||||
compose_mobile_button_popover_displayed ||
|
compose_mobile_button_popover_displayed ||
|
||||||
compose_control_buttons_popover_instance
|
compose_control_buttons_popover_instance ||
|
||||||
|
compose_enter_sends_popover_displayed
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,4 +131,46 @@ export function initialize() {
|
||||||
compose_control_buttons_popover_instance = undefined;
|
compose_control_buttons_popover_instance = undefined;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
delegate("body", {
|
||||||
|
...default_popover_props,
|
||||||
|
target: ".enter_sends",
|
||||||
|
placement: "top",
|
||||||
|
onShow(instance) {
|
||||||
|
on_show_prep(instance);
|
||||||
|
instance.setContent(
|
||||||
|
render_compose_select_enter_behaviour_popover({
|
||||||
|
enter_sends_true: user_settings.enter_sends,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
compose_enter_sends_popover_displayed = true;
|
||||||
|
},
|
||||||
|
onMount(instance) {
|
||||||
|
common.adjust_mac_shortcuts(".enter_sends_choices kbd");
|
||||||
|
|
||||||
|
$(instance.popper).one("click", ".enter_sends_choice", (e) => {
|
||||||
|
let selected_behaviour = $(e.currentTarget)
|
||||||
|
.find("input[type='radio']")
|
||||||
|
.attr("value");
|
||||||
|
selected_behaviour = selected_behaviour === "true"; // Convert to bool
|
||||||
|
user_settings.enter_sends = selected_behaviour;
|
||||||
|
$(`.enter_sends_${!selected_behaviour}`).hide();
|
||||||
|
$(`.enter_sends_${selected_behaviour}`).show();
|
||||||
|
|
||||||
|
// Refocus in the content box so you can continue typing or
|
||||||
|
// press Enter to send.
|
||||||
|
$("#compose-textarea").trigger("focus");
|
||||||
|
|
||||||
|
return channel.patch({
|
||||||
|
url: "/json/settings",
|
||||||
|
idempotent: true,
|
||||||
|
data: {enter_sends: selected_behaviour},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onHidden(instance) {
|
||||||
|
instance.destroy();
|
||||||
|
compose_enter_sends_popover_displayed = false;
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
import tippy, {delegate} from "tippy.js";
|
import tippy, {delegate} from "tippy.js";
|
||||||
|
|
||||||
|
import {$t} from "./i18n";
|
||||||
import * as message_lists from "./message_lists";
|
import * as message_lists from "./message_lists";
|
||||||
|
import * as popover_menus from "./popover_menus";
|
||||||
import * as reactions from "./reactions";
|
import * as reactions from "./reactions";
|
||||||
import * as rows from "./rows";
|
import * as rows from "./rows";
|
||||||
import * as timerender from "./timerender";
|
import * as timerender from "./timerender";
|
||||||
|
@ -185,4 +187,16 @@ export function initialize() {
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
delegate("body", {
|
||||||
|
target: [".enter_sends_true", ".enter_sends_false"],
|
||||||
|
content: $t({defaultMessage: "Change send shortcut"}),
|
||||||
|
onShow() {
|
||||||
|
// Don't show tooltip if the popover is displayed.
|
||||||
|
if (popover_menus.compose_enter_sends_popover_displayed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -441,12 +441,45 @@ input.recipient_box {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.enter_sends_choices {
|
||||||
|
.enter_sends_choice {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
padding-top: 4px;
|
||||||
|
|
||||||
|
input[type="radio"] {
|
||||||
|
position: relative;
|
||||||
|
top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
padding: 0 0 4px;
|
||||||
|
border-bottom: 1px solid hsla(0, 0%, 0%, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.enter_sends_choice_text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enter_sends_minor,
|
||||||
|
.enter_sends_minor kbd {
|
||||||
|
opacity: 0.9;
|
||||||
|
font-size: 11px;
|
||||||
|
color: hsl(0, 0%, 50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.enter_sends {
|
.enter_sends {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
|
position: relative;
|
||||||
|
top: -2px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
@media (width < $mm_min) {
|
@media (width < $mm_min) {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
|
@ -454,6 +487,7 @@ input.recipient_box {
|
||||||
|
|
||||||
kbd {
|
kbd {
|
||||||
height: 16px;
|
height: 16px;
|
||||||
|
padding: 0 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@ -465,8 +499,10 @@ input.recipient_box {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fa-exchange {
|
i {
|
||||||
margin: 0 4px;
|
padding-left: 3px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,12 +63,21 @@ body.dark-theme {
|
||||||
background-color: hsl(211, 28%, 14%);
|
background-color: hsl(211, 28%, 14%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.enter_sends kbd {
|
.enter_sends,
|
||||||
background-color: hsl(211, 29%, 14%);
|
.enter_sends_choices {
|
||||||
border-color: hsl(211, 29%, 14%);
|
|
||||||
box-shadow: inset 0 -1px 0 hsl(210, 5%, 34%, 0.2);
|
|
||||||
text-shadow: none;
|
|
||||||
color: hsl(236, 33%, 90%);
|
color: hsl(236, 33%, 90%);
|
||||||
|
|
||||||
|
kbd {
|
||||||
|
background-color: hsl(211, 29%, 14%);
|
||||||
|
border-color: hsl(211, 29%, 14%);
|
||||||
|
box-shadow: inset 0 -1px 0 hsl(210, 5%, 34%, 0.2);
|
||||||
|
text-shadow: none;
|
||||||
|
color: hsl(236, 33%, 90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.enter_sends_minor {
|
||||||
|
color: hsl(0, 0%, 80%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table.table-striped thead.table-sticky-headers th {
|
table.table-striped thead.table-sticky-headers th {
|
||||||
|
|
|
@ -105,21 +105,21 @@
|
||||||
<div class="compose_bottom_bottom_container">
|
<div class="compose_bottom_bottom_container">
|
||||||
<span id="compose_limit_indicator"></span>
|
<span id="compose_limit_indicator"></span>
|
||||||
<div class="enter_sends">
|
<div class="enter_sends">
|
||||||
<label id="enter-sends-label" class="compose_checkbox_label tippy-zulip-tooltip" data-tippy-content="Click to switch">
|
<span class="enter_sends_true">
|
||||||
<span class="enter_sends_true">
|
<kbd>Enter</kbd>
|
||||||
<kbd>Enter</kbd> {{t 'to send' }}
|
{{#tr}}
|
||||||
</span>
|
<kbd class="hide">Enter</kbd>
|
||||||
<span class="enter_sends_false">
|
<span>to send</span>
|
||||||
<kbd>Ctrl</kbd> + <kbd>Enter</kbd> {{t 'to send' }}
|
{{/tr}}
|
||||||
</span>
|
</span>
|
||||||
<i class="fa fa-exchange" aria-hidden="true"></i>
|
<span class="enter_sends_false">
|
||||||
<span class="enter_sends_true">
|
<kbd>Ctrl</kbd> + <kbd>Enter</kbd>
|
||||||
<kbd>Ctrl</kbd> + <kbd>Enter</kbd> {{t 'to add a new line' }}
|
{{#tr}}
|
||||||
</span>
|
<kbd class="hide">Enter</kbd>
|
||||||
<span class="enter_sends_false">
|
<span>to send</span>
|
||||||
<kbd>Enter</kbd> {{t 'to add a new line' }}
|
{{/tr}}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
<i class="fa fa-caret-down" aria-hidden="true"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<div class="enter_sends_choices grey-box">
|
||||||
|
<label class="enter_sends_choice">
|
||||||
|
<input type="radio" class="prop-element" value="true"{{#if enter_sends_true }} checked{{/if}} />
|
||||||
|
<div class="enter_sends_choice_text">
|
||||||
|
<span>
|
||||||
|
{{#tr}}
|
||||||
|
<z-button><kbd>Enter</kbd></z-button>
|
||||||
|
<span>to send</span>
|
||||||
|
{{/tr}}
|
||||||
|
</span>
|
||||||
|
<span class="enter_sends_minor">
|
||||||
|
{{#tr}}
|
||||||
|
<z-button><kbd>Ctrl</kbd> + <kbd>Enter</kbd></z-button>
|
||||||
|
<span>to add a new line</span>
|
||||||
|
{{/tr}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<label class="enter_sends_choice">
|
||||||
|
<input type="radio" class="prop-element" value="false"{{#unless enter_sends_true }} checked{{/unless}} />
|
||||||
|
<div class="enter_sends_choice_text">
|
||||||
|
<span>
|
||||||
|
{{#tr}}
|
||||||
|
<z-button><kbd>Ctrl</kbd> + <kbd>Enter</kbd></z-button>
|
||||||
|
<span>to send</span>
|
||||||
|
{{/tr}}
|
||||||
|
</span>
|
||||||
|
<span class="enter_sends_minor">
|
||||||
|
{{#tr}}
|
||||||
|
<z-button><kbd>Enter</kbd></z-button>
|
||||||
|
<span>to add a new line</span>
|
||||||
|
{{/tr}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
Loading…
Reference in New Issue