inline_topic_edit: Disable save button and show tooltip on empty topic.

This commit disables the save button when the topic name is considered
as empty as part of the `realm_mandatory_topics` being set to True.

Since disabled elements do not fire events, it is not possible to
trigger tippy tooltips on disabled elements – such as the Save button
in the inline topic edit UI. Thus this commit adds a tooltip to the
disabled save button by wrapping/unwrapping it inside a `span` wrapper
pragmatically via the `ui_util.disable_element_and_add_tooltip` and
`ui_util.enable_element_and_remove_tooltip` helper methods.
This commit is contained in:
Sayam Samal
2025-02-15 20:55:34 +05:30
committed by Tim Abbott
parent 196fcd5c0a
commit 4c9d47c390
5 changed files with 71 additions and 1 deletions

View File

@@ -57,6 +57,7 @@ import * as sub_store from "./sub_store.ts";
import * as timerender from "./timerender.ts";
import * as typing from "./typing.ts";
import * as ui_report from "./ui_report.ts";
import * as ui_util from "./ui_util.ts";
import * as upload from "./upload.ts";
import {the} from "./util.ts";
import * as util from "./util.ts";
@@ -453,6 +454,25 @@ function handle_inline_topic_edit_change(this: HTMLInputElement): void {
// as that probably means the user is trying to fix the error.
$inline_topic_edit_input.removeClass("invalid-input");
}
const $topic_edit_save_button = $inline_topic_edit_input
.closest(".topic_edit_form")
.find(".topic_edit_save");
if (realm.realm_mandatory_topics && util.is_topic_name_considered_empty(this.value)) {
// When the topic is mandatory in a realm and the new topic is considered empty,
// we disable the save button and show a tooltip with an error message.
ui_util.disable_element_and_add_tooltip(
$topic_edit_save_button,
$t({defaultMessage: "Topics are required in this organization."}),
);
return;
}
if ($topic_edit_save_button.parent().hasClass("disabled-tooltip")) {
// If we reach here, it means the save button was disabled previously
// and the user has started typing in the input field, probably to fix
// the error. So, we re-enable the save button and remove the tooltip.
ui_util.enable_element_and_remove_tooltip($topic_edit_save_button);
}
}
function timer_text(seconds_left: number): string {

View File

@@ -696,4 +696,13 @@ export function initialize(): void {
instance.destroy();
},
});
tippy.delegate("body", {
target: ".disabled-tooltip",
trigger: "focus mouseenter",
appendTo: () => document.body,
onHidden(instance) {
instance.destroy();
},
});
}

View File

@@ -1,4 +1,5 @@
import $ from "jquery";
import type * as tippy from "tippy.js";
import * as blueslip from "./blueslip.ts";
import * as hash_parser from "./hash_parser.ts";
@@ -271,3 +272,31 @@ export function matches_viewport_state(state_string: string): boolean {
}
return false;
}
export function disable_element_and_add_tooltip($element: JQuery, tooltip_text: string): void {
// Since disabled elements do not fire events, it is not possible to trigger
// tippy tooltips on disabled elements. So, as a workaround, we wrap the
// disabled element in a span and show the tooltip on this wrapper instead.
// https://atomiks.github.io/tippyjs/v6/constructor/#disabled-elements
if ($element.prop("disabled")) {
// If already disabled, there's nothing to do.
return;
}
$element.prop("disabled", true);
const $tooltip_target_wrapper = $("<span>");
$tooltip_target_wrapper.addClass("disabled-tooltip");
$tooltip_target_wrapper.attr("data-tippy-content", tooltip_text).attr("tabindex", "0");
$element.wrap($tooltip_target_wrapper);
}
export function enable_element_and_remove_tooltip($element: JQuery): void {
// This method reverses the effects of disable_element_and_add_tooltip,
// and explicitly removes any attached tooltips on the wrapper to prevent
// ghost tooltips.
$element.prop("disabled", false);
const tooltip_wrapper: tippy.ReferenceElement = $element.parent(".disabled-tooltip")[0]!;
if (tooltip_wrapper?._tippy) {
tooltip_wrapper._tippy.destroy();
}
$element.unwrap(".disabled-tooltip");
}

View File

@@ -46,6 +46,12 @@
outline-offset: 2px;
clip-path: inset(-3px);
}
&:disabled {
cursor: default;
pointer-events: none;
opacity: 0.5;
}
}
.action-button-label {
@@ -409,6 +415,12 @@
outline-offset: 2px;
clip-path: inset(-3px);
}
&:disabled {
cursor: default;
pointer-events: none;
opacity: 0.5;
}
}
.icon-button-neutral {

View File

@@ -284,7 +284,7 @@
/* these are converting grey things to "new grey".
:disabled rules are exploded for CSS selector performance reasons. */
button:disabled,
button:disabled:not(.action-button, .icon-button),
option:disabled,
select:disabled,
textarea:disabled,