mirror of https://github.com/zulip/zulip.git
drafts: Add functionality to bulk delete drafts.
Fixes #19360. Co-authored-by: Satyam Bansal <sbansal1999@gmail.com>
This commit is contained in:
parent
e4048de0a9
commit
fed866449d
|
@ -617,6 +617,7 @@ export function launch() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
update_rendered_drafts(narrow_drafts.length > 0, other_drafts.length > 0);
|
update_rendered_drafts(narrow_drafts.length > 0, other_drafts.length > 0);
|
||||||
|
update_bulk_delete_ui();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup_event_handlers() {
|
function setup_event_handlers() {
|
||||||
|
@ -638,8 +639,37 @@ export function launch() {
|
||||||
const $draft_row = $(this).closest(".overlay-message-row");
|
const $draft_row = $(this).closest(".overlay-message-row");
|
||||||
|
|
||||||
remove_draft($draft_row);
|
remove_draft($draft_row);
|
||||||
|
update_bulk_delete_ui();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$("#drafts_table .overlay_message_controls .draft-selection-checkbox").on("click", (e) => {
|
||||||
|
const is_checked = is_checkbox_icon_checked($(e.target));
|
||||||
|
toggle_checkbox_icon_state($(e.target), !is_checked);
|
||||||
|
update_bulk_delete_ui();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".select-drafts-button").on("click", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const $unchecked_checkboxes = $(".draft-selection-checkbox").filter(function () {
|
||||||
|
return !is_checkbox_icon_checked($(this));
|
||||||
|
});
|
||||||
|
const check_boxes = $unchecked_checkboxes.length > 0;
|
||||||
|
$(".draft-selection-checkbox").each(function () {
|
||||||
|
toggle_checkbox_icon_state($(this), check_boxes);
|
||||||
|
});
|
||||||
|
update_bulk_delete_ui();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".delete-selected-drafts-button").on("click", () => {
|
||||||
|
$(".drafts-list")
|
||||||
|
.find(".draft-selection-checkbox.fa-check-square")
|
||||||
|
.closest(".overlay-message-row")
|
||||||
|
.each(function () {
|
||||||
|
remove_draft($(this));
|
||||||
|
});
|
||||||
|
update_bulk_delete_ui();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const drafts = draft_model.get();
|
const drafts = draft_model.get();
|
||||||
|
@ -663,6 +693,35 @@ export function launch() {
|
||||||
setup_event_handlers();
|
setup_event_handlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function update_bulk_delete_ui() {
|
||||||
|
const $unchecked_checkboxes = $(".draft-selection-checkbox").filter(function () {
|
||||||
|
return !is_checkbox_icon_checked($(this));
|
||||||
|
});
|
||||||
|
const $checked_checkboxes = $(".draft-selection-checkbox").filter(function () {
|
||||||
|
return is_checkbox_icon_checked($(this));
|
||||||
|
});
|
||||||
|
const $select_drafts_button = $(".select-drafts-button");
|
||||||
|
const $select_state_indicator = $(".select-drafts-button .select-state-indicator");
|
||||||
|
const $delete_selected_drafts_button = $(".delete-selected-drafts-button");
|
||||||
|
|
||||||
|
if ($checked_checkboxes.length > 0) {
|
||||||
|
$delete_selected_drafts_button.prop("disabled", false);
|
||||||
|
if ($unchecked_checkboxes.length === 0) {
|
||||||
|
toggle_checkbox_icon_state($select_state_indicator, true);
|
||||||
|
} else {
|
||||||
|
toggle_checkbox_icon_state($select_state_indicator, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($unchecked_checkboxes.length > 0) {
|
||||||
|
toggle_checkbox_icon_state($select_state_indicator, false);
|
||||||
|
$delete_selected_drafts_button.prop("disabled", true);
|
||||||
|
} else {
|
||||||
|
$select_drafts_button.hide();
|
||||||
|
$delete_selected_drafts_button.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function open_overlay() {
|
function open_overlay() {
|
||||||
sync_count();
|
sync_count();
|
||||||
overlays.open_overlay({
|
overlays.open_overlay({
|
||||||
|
@ -675,6 +734,19 @@ function open_overlay() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_checkbox_icon_checked($checkbox) {
|
||||||
|
return $checkbox.hasClass("fa-check-square");
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle_checkbox_icon_state($checkbox, checked) {
|
||||||
|
$checkbox.parent().attr("aria-checked", checked);
|
||||||
|
if (checked) {
|
||||||
|
$checkbox.removeClass("fa-square-o").addClass("fa-check-square");
|
||||||
|
} else {
|
||||||
|
$checkbox.removeClass("fa-check-square").addClass("fa-square-o");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function initialize() {
|
export function initialize() {
|
||||||
remove_old_drafts();
|
remove_old_drafts();
|
||||||
|
|
||||||
|
|
|
@ -143,13 +143,46 @@ export function initialize() {
|
||||||
// below specify the target directly, elements using those should
|
// below specify the target directly, elements using those should
|
||||||
// not have the tippy-zulip-tooltip class.
|
// not have the tippy-zulip-tooltip class.
|
||||||
|
|
||||||
$("body").on("blur", ".message_control_button", (e) => {
|
delegate("body", {
|
||||||
// Remove tooltip when user is trying to tab through all the icons.
|
target: ".draft-selection-tooltip",
|
||||||
// If user tabs slowly, tooltips are displayed otherwise they are
|
delay: LONG_HOVER_DELAY,
|
||||||
// destroyed before they can be displayed.
|
appendTo: () => document.body,
|
||||||
e.currentTarget?._tippy?.destroy();
|
onShow(instance) {
|
||||||
|
let content = $t({defaultMessage: "Select draft"});
|
||||||
|
const $elem = $(instance.reference);
|
||||||
|
if ($($elem).parent().find(".draft-selection-checkbox").hasClass("fa-check-square")) {
|
||||||
|
content = $t({defaultMessage: "Deselect draft"});
|
||||||
|
}
|
||||||
|
instance.setContent(content);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
delegate("body", {
|
||||||
|
target: ".delete-selected-drafts-button-container",
|
||||||
|
appendTo: () => document.body,
|
||||||
|
onShow(instance) {
|
||||||
|
let content = $t({defaultMessage: "Delete all selected drafts"});
|
||||||
|
const $elem = $(instance.reference);
|
||||||
|
if ($($elem).find(".delete-selected-drafts-button").is(":disabled")) {
|
||||||
|
content = $t({defaultMessage: "No drafts selected"});
|
||||||
|
}
|
||||||
|
instance.setContent(content);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
$("body").on(
|
||||||
|
"blur",
|
||||||
|
".message_control_button, .delete-selected-drafts-button-container",
|
||||||
|
(e) => {
|
||||||
|
// Remove tooltip when user is trying to tab through all the icons.
|
||||||
|
// If user tabs slowly, tooltips are displayed otherwise they are
|
||||||
|
// destroyed before they can be displayed.
|
||||||
|
e.currentTarget?._tippy?.destroy();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
delegate("body", {
|
delegate("body", {
|
||||||
target: [
|
target: [
|
||||||
"#streams_header .sidebar-title",
|
"#streams_header .sidebar-title",
|
||||||
|
|
|
@ -879,6 +879,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.drafts-container .header-body .delete-drafts-group > *:focus {
|
||||||
|
background-color: hsl(228deg 11% 17%);
|
||||||
|
}
|
||||||
|
|
||||||
& thead,
|
& thead,
|
||||||
.drafts-container .drafts-header,
|
.drafts-container .drafts-header,
|
||||||
.nav > li > a:focus,
|
.nav > li > a:focus,
|
||||||
|
|
|
@ -1,4 +1,60 @@
|
||||||
.drafts-container {
|
.drafts-container {
|
||||||
|
.header-body {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
|
.removed-drafts {
|
||||||
|
text-align: left;
|
||||||
|
margin-left: 25px;
|
||||||
|
|
||||||
|
@media (width < $lg_min) {
|
||||||
|
text-align: center;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-drafts-group {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.delete-selected-drafts-button {
|
||||||
|
&:focus {
|
||||||
|
background-color: hsl(0deg 0% 93%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-drafts-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
margin-right: 25px;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background-color: hsl(0deg 0% 93%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-state-indicator {
|
||||||
|
width: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (width < $lg_min) {
|
||||||
|
margin-top: 5px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (width < $lg_min) {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.drafts-list {
|
.drafts-list {
|
||||||
& h2 {
|
& h2 {
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
|
@ -6,4 +62,12 @@
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.draft-selection-checkbox {
|
||||||
|
margin-top: 5px;
|
||||||
|
/* Required to make sure that the checkbox icon stays inside
|
||||||
|
the grid. Any value greater than 13px (original width of
|
||||||
|
the checkbox icon) will work. */
|
||||||
|
width: 15px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,9 @@
|
||||||
<div class="overlay_message_controls">
|
<div class="overlay_message_controls">
|
||||||
<i class="fa fa-pencil fa-lg restore-overlay-message tippy-zulip-tooltip" aria-hidden="true" data-tooltip-template-id="restore-draft-tooltip-template"></i>
|
<i class="fa fa-pencil fa-lg restore-overlay-message tippy-zulip-tooltip" aria-hidden="true" data-tooltip-template-id="restore-draft-tooltip-template"></i>
|
||||||
<i class="fa fa-trash-o fa-lg delete-overlay-message tippy-zulip-tooltip" aria-hidden="true" data-tooltip-template-id="delete-draft-tooltip-template"></i>
|
<i class="fa fa-trash-o fa-lg delete-overlay-message tippy-zulip-tooltip" aria-hidden="true" data-tooltip-template-id="delete-draft-tooltip-template"></i>
|
||||||
|
<div class="draft-selection-tooltip">
|
||||||
|
<i class="fa fa-square-o fa-lg draft-selection-checkbox" aria-hidden="true"></i>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="message_content rendered_markdown restore-overlay-message tippy-zulip-delayed-tooltip" data-tooltip-template-id="restore-draft-tooltip-template">{{rendered_markdown content}}</div>
|
<div class="message_content rendered_markdown restore-overlay-message tippy-zulip-delayed-tooltip" data-tooltip-template-id="restore-draft-tooltip-template">{{rendered_markdown content}}</div>
|
||||||
|
|
|
@ -6,10 +6,23 @@
|
||||||
<div class="exit">
|
<div class="exit">
|
||||||
<span class="exit-sign">×</span>
|
<span class="exit-sign">×</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="removed-drafts">
|
<div class="header-body">
|
||||||
{{t "Drafts are not synced to other devices and browsers." }}
|
<div class="removed-drafts">
|
||||||
<br />
|
{{t "Drafts are not synced to other devices and browsers." }}
|
||||||
{{#tr}}Drafts older than <strong>{draft_lifetime}</strong> days are automatically removed.{{/tr}}
|
<br />
|
||||||
|
{{#tr}}Drafts older than <strong>{draft_lifetime}</strong> days are automatically removed.{{/tr}}
|
||||||
|
</div>
|
||||||
|
<div class="delete-drafts-group">
|
||||||
|
<div class="delete-selected-drafts-button-container">
|
||||||
|
<button class="button small rounded delete-selected-drafts-button" type="button" disabled>
|
||||||
|
<i class="fa fa-trash-o fa-lg" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button class="button small rounded select-drafts-button" role="checkbox" aria-checked="false">
|
||||||
|
<span>{{t "Select all drafts" }}</span>
|
||||||
|
<i class="fa fa-square-o fa-lg select-state-indicator" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="drafts-list overlay-messages-list">
|
<div class="drafts-list overlay-messages-list">
|
||||||
|
|
|
@ -610,6 +610,7 @@ test("format_drafts", ({override_rewire, mock_template}) => {
|
||||||
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
|
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
|
||||||
|
|
||||||
$.create("#drafts_table .overlay-message-row", {children: []});
|
$.create("#drafts_table .overlay-message-row", {children: []});
|
||||||
|
$(".draft-selection-checkbox").filter = () => [];
|
||||||
drafts.launch();
|
drafts.launch();
|
||||||
|
|
||||||
$.clear_all_elements();
|
$.clear_all_elements();
|
||||||
|
@ -625,6 +626,7 @@ test("format_drafts", ({override_rewire, mock_template}) => {
|
||||||
|
|
||||||
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
|
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
|
||||||
|
|
||||||
|
$(".draft-selection-checkbox").filter = () => [];
|
||||||
drafts.launch();
|
drafts.launch();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -770,5 +772,6 @@ test("filter_drafts", ({override_rewire, mock_template}) => {
|
||||||
compose_state.private_message_recipient(aaron.email);
|
compose_state.private_message_recipient(aaron.email);
|
||||||
|
|
||||||
$.create("#drafts_table .overlay-message-row", {children: []});
|
$.create("#drafts_table .overlay-message-row", {children: []});
|
||||||
|
$(".draft-selection-checkbox").filter = () => [];
|
||||||
drafts.launch();
|
drafts.launch();
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue