mirror of
https://github.com/zulip/zulip.git
synced 2025-11-05 22:43:42 +00:00
hotkey.js: Add hotkey for drafts.
* 'd' in message view opens drafts. This also adds hotkeys within the drafts UI: * Up/down arrow keys navigate the drafts. * Pressing enter edits the selected draft. * Pressing backspace deletes the selected draft. Some variable names tweaked by tabbott.
This commit is contained in:
@@ -14,6 +14,11 @@
|
||||
set_global('activity', {
|
||||
});
|
||||
|
||||
set_global('drafts', {
|
||||
drafts_handle_events: function () { return; },
|
||||
drafts_overlay_open: function () { return; },
|
||||
});
|
||||
|
||||
set_global('$', function () {
|
||||
return {
|
||||
// Hack: Used for reactions hotkeys; may want to restructure.
|
||||
@@ -139,7 +144,7 @@ function stubbing(func_name_to_stub, test_function) {
|
||||
|
||||
// Unmapped keys should immediately return false, without
|
||||
// calling any functions outside of hotkey.js.
|
||||
assert_unmapped('abdefhlmoptuxyz');
|
||||
assert_unmapped('abefhlmoptuxyz');
|
||||
assert_unmapped('BEFHILNOQTWXYZ');
|
||||
|
||||
// We have to skip some checks due to the way the code is
|
||||
@@ -193,6 +198,7 @@ function stubbing(func_name_to_stub, test_function) {
|
||||
assert_mapping('C', 'compose_actions.start');
|
||||
assert_mapping('P', 'narrow.by');
|
||||
assert_mapping('g', 'gear_menu.open');
|
||||
assert_mapping('d', 'drafts.toggle');
|
||||
|
||||
// Next, test keys that only work on a selected message.
|
||||
var message_view_only_keys = '@*+rRjJkKsSvi:GM';
|
||||
|
||||
@@ -203,9 +203,120 @@ exports.setup_page = function (callback) {
|
||||
populate_and_fill();
|
||||
};
|
||||
|
||||
exports.drafts_overlay_open = function () {
|
||||
return $("#draft_overlay").hasClass("show");
|
||||
};
|
||||
|
||||
exports.drafts_handle_events = function (e, event_key) {
|
||||
var draft_arrow = draft_model.get();
|
||||
var draft_id_arrow = Object.getOwnPropertyNames(draft_arrow);
|
||||
// This detects up arrow key presses when the draft overlay
|
||||
// is open and scrolls through the drafts.
|
||||
if (event_key === "up_arrow") {
|
||||
if ($(".draft-info-box:focus")[0] === undefined) {
|
||||
if (draft_id_arrow.length > 0) {
|
||||
var last_draft = draft_id_arrow[draft_id_arrow.length-1];
|
||||
var last_draft_element = document.querySelectorAll('[data-draft-id="' + last_draft + '"]');
|
||||
var focus_up_element = last_draft_element[0].children[0];
|
||||
focus_up_element.focus();
|
||||
}
|
||||
}
|
||||
var focus_draft_up_row = $(".draft-info-box:focus")[0].parentElement;
|
||||
var prev_focus_draft_row = $(focus_draft_up_row).prev();
|
||||
if ($(".draft-info-box:first")[0].parentElement === prev_focus_draft_row[0]) {
|
||||
$(".drafts-list")[0].scrollTop = 0;
|
||||
}
|
||||
if (prev_focus_draft_row[0].children[0] !== undefined) {
|
||||
prev_focus_draft_row[0].children[0].focus();
|
||||
// If the next draft is cut off, scroll more.
|
||||
if (prev_focus_draft_row.position().top < 55) {
|
||||
// 55 is the minimum distance from the top that will require extra scrolling.
|
||||
$(".drafts-list")[0].scrollTop = $(".drafts-list")[0].scrollTop - (55 - prev_focus_draft_row.position().top);
|
||||
}
|
||||
e.preventDefault();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// This detects down arrow key presses when the draft overlay
|
||||
// is open and scrolls through the drafts.
|
||||
if (event_key === "down_arrow") {
|
||||
if ($(".draft-info-box:focus")[0] === undefined) {
|
||||
if (draft_id_arrow.length > 0) {
|
||||
var first_draft = draft_id_arrow[0];
|
||||
var first_draft_element = document.querySelectorAll('[data-draft-id="' + first_draft + '"]');
|
||||
var focus_down_element = first_draft_element[0].children[0];
|
||||
focus_down_element.focus();
|
||||
}
|
||||
}
|
||||
var focus_draft_down_row = $(".draft-info-box:focus")[0].parentElement;
|
||||
var next_focus_draft_row = $(focus_draft_down_row).next();
|
||||
if ($(".draft-info-box:last")[0].parentElement === next_focus_draft_row[0]) {
|
||||
$(".drafts-list")[0].scrollTop = $('.drafts-list')[0].scrollHeight - $('.drafts-list').height();
|
||||
}
|
||||
if (next_focus_draft_row[0] !== undefined) {
|
||||
next_focus_draft_row[0].children[0].focus();
|
||||
// If the next draft is cut off, scroll more.
|
||||
if (next_focus_draft_row.position() !== undefined) {
|
||||
var dist_from_top = next_focus_draft_row.position().top;
|
||||
var total_dist = dist_from_top + next_focus_draft_row[0].clientHeight;
|
||||
var dist_from_bottom = $(".drafts-container")[0].clientHeight - total_dist;
|
||||
if (dist_from_bottom < -4) {
|
||||
//-4 is the min dist from the bottom that will require extra scrolling.
|
||||
$(".drafts-list")[0].scrollTop = $(".drafts-list")[0].scrollTop + 2 - (dist_from_bottom);
|
||||
}
|
||||
}
|
||||
e.preventDefault();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Allows user to delete drafts with backspace
|
||||
if (event_key === "backspace") {
|
||||
var elt = document.activeElement;
|
||||
if (elt.parentElement.hasAttribute("data-draft-id")) {
|
||||
var focused_draft = $(elt.parentElement)[0].getAttribute("data-draft-id");
|
||||
var focus_draft_back_row = $(elt)[0].parentElement;
|
||||
var backnext_focus_draft_row = $(focus_draft_back_row).next();
|
||||
var backprev_focus_draft_row = $(focus_draft_back_row).prev();
|
||||
var delete_id;
|
||||
if (backnext_focus_draft_row[0] !== undefined) {
|
||||
delete_id = backnext_focus_draft_row[0].getAttribute("data-draft-id");
|
||||
} else if (backprev_focus_draft_row[0] !== undefined) {
|
||||
delete_id = backprev_focus_draft_row[0].getAttribute("data-draft-id");
|
||||
}
|
||||
drafts.draft_model.deleteDraft(focused_draft);
|
||||
document.activeElement.parentElement.remove();
|
||||
var new_focus_element = document.querySelectorAll('[data-draft-id="' + delete_id + '"]');
|
||||
if (new_focus_element[0] !== undefined) {
|
||||
new_focus_element[0].children[0].focus();
|
||||
}
|
||||
if ($("#drafts_table .draft-row").length === 0) {
|
||||
$('#drafts_table .no-drafts').show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.toggle = function () {
|
||||
if (exports.drafts_overlay_open()) {
|
||||
modals.close_modal("drafts");
|
||||
} else {
|
||||
exports.launch();
|
||||
}
|
||||
};
|
||||
|
||||
exports.launch = function () {
|
||||
exports.setup_page(function () {
|
||||
$("#draft_overlay").addClass("show");
|
||||
var draft_list = drafts.draft_model.get();
|
||||
var draft_id_list = Object.getOwnPropertyNames(draft_list);
|
||||
if (draft_id_list.length > 0) {
|
||||
var last_draft = draft_id_list[draft_id_list.length-1];
|
||||
var last_draft_element = document.querySelectorAll('[data-draft-id="' + last_draft + '"]');
|
||||
var focus_element = last_draft_element[0].children[0];
|
||||
focus_element.focus();
|
||||
$(".drafts-list")[0].scrollTop = $('.drafts-list')[0].scrollHeight - $('.drafts-list').height();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@ var keypress_mappings = {
|
||||
85: {name: 'keyboard_sub', message_view_only: false}, //'U'
|
||||
86: {name: 'view_selected_stream', message_view_only: false}, //'V'
|
||||
99: {name: 'compose', message_view_only: true}, // 'c'
|
||||
100: {name: 'open_drafts', message_view_only: false}, // 'd'
|
||||
103: {name: 'gear_menu', message_view_only: true}, // 'g'
|
||||
105: {name: 'message_actions', message_view_only: true}, // 'i'
|
||||
106: {name: 'vim_down', message_view_only: true}, // 'j'
|
||||
@@ -207,7 +208,7 @@ exports.process_escape_key = function (e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($("#draft_overlay").hasClass("show")) {
|
||||
if (drafts.drafts_overlay_open()) {
|
||||
modals.close_modal("drafts");
|
||||
return true;
|
||||
}
|
||||
@@ -333,6 +334,21 @@ exports.process_enter_key = function (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This handles when pressing enter while looking at drafts.
|
||||
// It restores draft that is focused.
|
||||
if (drafts.drafts_overlay_open()) {
|
||||
var draft_list = drafts.draft_model.get();
|
||||
if (document.activeElement.parentElement.hasAttribute("data-draft-id")) {
|
||||
var focused_draft = document.activeElement.parentElement.getAttribute("data-draft-id");
|
||||
drafts.restore_draft(focused_draft);
|
||||
} else {
|
||||
var draft_id_list = Object.getOwnPropertyNames(draft_list);
|
||||
var first_draft = draft_id_list[draft_id_list.length-1];
|
||||
drafts.restore_draft(first_draft);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we're on a button or a link and have pressed enter, let the
|
||||
// browser handle the keypress
|
||||
//
|
||||
@@ -435,6 +451,10 @@ exports.process_hotkey = function (e, hotkey) {
|
||||
return exports.process_escape_key(e);
|
||||
}
|
||||
|
||||
if (drafts.drafts_overlay_open()) {
|
||||
drafts.drafts_handle_events(e, event_name);
|
||||
}
|
||||
|
||||
if (hotkey.message_view_only && ui_state.home_tab_obscured()) {
|
||||
if ((event_name === 'up_arrow' || event_name === 'down_arrow') && exports.is_subs()) {
|
||||
subs.switch_rows(event_name);
|
||||
@@ -598,6 +618,9 @@ exports.process_hotkey = function (e, hotkey) {
|
||||
subs.new_stream_clicked();
|
||||
}
|
||||
return true;
|
||||
case 'open_drafts':
|
||||
drafts.toggle();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (current_msg_list.empty()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="draft-row" data-draft-id="{{draft_id}}">
|
||||
<div class="draft-info-box">
|
||||
<div class="draft-info-box" tabindex="0">
|
||||
{{#if is_stream}}
|
||||
<div class="message_header message_header_stream">
|
||||
<div class="message-header-contents">
|
||||
|
||||
@@ -57,6 +57,8 @@ Zulip keyboard shortcuts are divided into four categories:
|
||||
shortcut allows the user to send the message that they've written.
|
||||
* **Cancel compose**: `Esc` - This shortcut allows the user to cancel
|
||||
and discard their unsent message.
|
||||
* **View drafts**: `d` - This shortcut allows the user to open the
|
||||
drafts overlay.
|
||||
|
||||
## Narrowing
|
||||
|
||||
|
||||
@@ -80,6 +80,10 @@
|
||||
<td class="hotkey">Esc</td>
|
||||
<td class="definition">{% trans %}Cancel compose{% endtrans %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="hotkey">d</td>
|
||||
<td class="definition">{% trans %}View drafts{% endtrans %}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user