custom_emoji: Convert inline form to modal.

Fixes part of #21298.
This commit is contained in:
Ganesh Pawar 2022-03-29 22:16:59 +05:30 committed by Tim Abbott
parent df001db1a9
commit b7335d0dec
6 changed files with 186 additions and 152 deletions

View File

@ -9,7 +9,7 @@ const $ = require("../zjsunit/zjquery");
const upload_widget = mock_esm("../../static/js/upload_widget"); const upload_widget = mock_esm("../../static/js/upload_widget");
const settings_emoji = zrequire("settings_emoji"); const settings_emoji = zrequire("settings_emoji");
run_test("build_emoji_upload_widget", () => { run_test("add_custom_emoji_post_render", () => {
let build_widget_stub = false; let build_widget_stub = false;
upload_widget.build_widget = ( upload_widget.build_widget = (
get_file_input, get_file_input,
@ -25,6 +25,6 @@ run_test("build_emoji_upload_widget", () => {
assert.deepEqual(upload_button, $("#emoji_upload_button")); assert.deepEqual(upload_button, $("#emoji_upload_button"));
build_widget_stub = true; build_widget_stub = true;
}; };
settings_emoji.build_emoji_upload_widget(); settings_emoji.add_custom_emoji_post_render();
assert.ok(build_widget_stub); assert.ok(build_widget_stub);
}); });

View File

@ -179,21 +179,15 @@ async function test_organization_permissions(page: Page): Promise<void> {
} }
async function test_add_emoji(page: Page): Promise<void> { async function test_add_emoji(page: Page): Promise<void> {
await common.fill_form(page, "form.admin-emoji-form", {name: "zulip logo"}); await common.fill_form(page, "#add-custom-emoji-form", {name: "zulip logo"});
const emoji_upload_handle = await page.$("#emoji_file_input"); const emoji_upload_handle = await page.$("#emoji_file_input");
assert.ok(emoji_upload_handle); assert.ok(emoji_upload_handle);
await (emoji_upload_handle as ElementHandle<HTMLInputElement>).uploadFile( await (emoji_upload_handle as ElementHandle<HTMLInputElement>).uploadFile(
"static/images/logo/zulip-icon-128x128.png", "static/images/logo/zulip-icon-128x128.png",
); );
await page.click("#admin_emoji_submit"); await page.click("#add-custom-emoji-modal .dialog_submit_button");
await common.wait_for_micromodal_to_close(page);
const emoji_status = "div#admin-emoji-status";
await page.waitForSelector(emoji_status, {visible: true});
assert.strictEqual(
await common.get_text_from_selector(page, emoji_status),
"Custom emoji added!",
);
await page.waitForSelector("tr#emoji_zulip_logo", {visible: true}); await page.waitForSelector("tr#emoji_zulip_logo", {visible: true});
assert.strictEqual( assert.strictEqual(
@ -217,7 +211,8 @@ async function test_delete_emoji(page: Page): Promise<void> {
async function test_custom_realm_emoji(page: Page): Promise<void> { async function test_custom_realm_emoji(page: Page): Promise<void> {
await page.click("li[data-section='emoji-settings']"); await page.click("li[data-section='emoji-settings']");
await page.waitForSelector(".admin-emoji-form", {visible: true}); await page.click("#add-custom-emoji-button");
await common.wait_for_micromodal_to_open(page);
await test_add_emoji(page); await test_add_emoji(page);
await test_delete_emoji(page); await test_delete_emoji(page);

View File

@ -3,6 +3,7 @@ import $ from "jquery";
import emoji_codes from "../generated/emoji/emoji_codes.json"; import emoji_codes from "../generated/emoji/emoji_codes.json";
import render_confirm_deactivate_custom_emoji from "../templates/confirm_dialog/confirm_deactivate_custom_emoji.hbs"; import render_confirm_deactivate_custom_emoji from "../templates/confirm_dialog/confirm_deactivate_custom_emoji.hbs";
import emoji_settings_warning_modal from "../templates/confirm_dialog/confirm_emoji_settings_warning.hbs"; import emoji_settings_warning_modal from "../templates/confirm_dialog/confirm_emoji_settings_warning.hbs";
import render_add_emoji from "../templates/settings/add_emoji.hbs";
import render_admin_emoji_list from "../templates/settings/admin_emoji_list.hbs"; import render_admin_emoji_list from "../templates/settings/admin_emoji_list.hbs";
import render_settings_emoji_settings_tip from "../templates/settings/emoji_settings_tip.hbs"; import render_settings_emoji_settings_tip from "../templates/settings/emoji_settings_tip.hbs";
@ -47,10 +48,10 @@ export function update_custom_emoji_ui() {
$("#emoji-settings").find(".emoji-settings-tip-container").html(rendered_tip); $("#emoji-settings").find(".emoji-settings-tip-container").html(rendered_tip);
if (!settings_data.user_can_add_custom_emoji()) { if (!settings_data.user_can_add_custom_emoji()) {
$(".add-emoji-text").hide(); $(".add-emoji-text").hide();
$(".admin-emoji-form").hide(); $("#add-custom-emoji-button").hide();
} else { } else {
$(".add-emoji-text").show(); $(".add-emoji-text").show();
$(".admin-emoji-form").show(); $("#add-custom-emoji-button").show();
} }
populate_emoji(); populate_emoji();
@ -138,7 +139,16 @@ export function populate_emoji() {
loading.destroy_indicator($("#admin_page_emoji_loading_indicator")); loading.destroy_indicator($("#admin_page_emoji_loading_indicator"));
} }
export function build_emoji_upload_widget() { export function add_custom_emoji_post_render() {
$("#add-custom-emoji-modal .dialog_submit_button").prop("disabled", true);
$("#add-custom-emoji-form").on("input", "input", () => {
$("#add-custom-emoji-modal .dialog_submit_button").prop(
"disabled",
$("#emoji_name").val() === "" || $("#emoji_file_input").val() === "",
);
});
const get_file_input = function () { const get_file_input = function () {
return $("#emoji_file_input"); return $("#emoji_file_input");
}; };
@ -149,8 +159,11 @@ export function build_emoji_upload_widget() {
const $upload_button = $("#emoji_upload_button"); const $upload_button = $("#emoji_upload_button");
const $preview_text = $("#emoji_preview_text"); const $preview_text = $("#emoji_preview_text");
const $preview_image = $("#emoji_preview_image"); const $preview_image = $("#emoji_preview_image");
const $placeholder_icon = $("#emoji_placeholder_icon");
return upload_widget.build_widget( $preview_image.hide();
upload_widget.build_widget(
get_file_input, get_file_input,
$file_name_field, $file_name_field,
$input_error, $input_error,
@ -159,11 +172,130 @@ export function build_emoji_upload_widget() {
$preview_text, $preview_text,
$preview_image, $preview_image,
); );
get_file_input().on("input", () => {
$placeholder_icon.hide();
$preview_image.show();
});
$preview_text.show();
$clear_button.on("click", (e) => {
e.stopPropagation();
e.preventDefault();
$("#add-custom-emoji-modal .dialog_submit_button").prop("disabled", true);
$preview_image.hide();
$placeholder_icon.show();
$preview_text.show();
$preview_image.attr("src", "/static/images/default-avatar.png");
});
}
function show_modal() {
const html_body = render_add_emoji();
function add_custom_emoji(e) {
e.preventDefault();
e.stopPropagation();
dialog_widget.show_dialog_spinner();
const $emoji_status = $("#dialog_error");
const emoji = {};
function submit_custom_emoji_request(formData) {
channel.post({
url: "/json/realm/emoji/" + encodeURIComponent(emoji.name),
data: formData,
cache: false,
processData: false,
contentType: false,
success() {
dialog_widget.close_modal();
},
error(xhr) {
$("#dialog_error").hide();
dialog_widget.hide_dialog_spinner();
const errors = JSON.parse(xhr.responseText).msg;
xhr.responseText = JSON.stringify({msg: errors});
ui_report.error($t_html({defaultMessage: "Failed"}), xhr, $emoji_status);
},
});
}
for (const obj of $("#add-custom-emoji-form").serializeArray()) {
emoji[obj.name] = obj.value;
}
if (emoji.name.trim() === "") {
ui_report.client_error(
$t_html({defaultMessage: "Failed: Emoji name is required."}),
$emoji_status,
);
dialog_widget.hide_dialog_spinner();
return;
}
if (is_custom_emoji(emoji.name)) {
ui_report.client_error(
$t_html({
defaultMessage: "Failed: A custom emoji with this name already exists.",
}),
$emoji_status,
);
dialog_widget.hide_dialog_spinner();
return;
}
const formData = new FormData();
for (const [i, file] of Array.prototype.entries.call($("#emoji_file_input")[0].files)) {
formData.append("file-" + i, file);
}
if (is_default_emoji(emoji.name)) {
if (!page_params.is_admin) {
ui_report.client_error(
$t_html({
defaultMessage:
"Failed: There is a default emoji with this name. Only administrators can override default emoji.",
}),
$emoji_status,
);
dialog_widget.hide_dialog_spinner();
return;
}
dialog_widget.close_modal(() => {
const html_body = emoji_settings_warning_modal({
emoji_name: emoji.name,
});
confirm_dialog.launch({
html_heading: $t_html({defaultMessage: "Override default emoji?"}),
html_body,
on_click: () => submit_custom_emoji_request(formData),
});
});
} else {
submit_custom_emoji_request(formData);
}
}
dialog_widget.launch({
html_heading: $t_html({defaultMessage: "Add a new emoji"}),
html_body,
html_submit_button: $t_html({defaultMessage: "Confirm"}),
id: "add-custom-emoji-modal",
loading_spinner: true,
on_click: add_custom_emoji,
post_render: add_custom_emoji_post_render,
});
} }
export function set_up() { export function set_up() {
meta.loaded = true; meta.loaded = true;
$("#add-custom-emoji-button").on("click", show_modal);
loading.make_indicator($("#admin_page_emoji_loading_indicator")); loading.make_indicator($("#admin_page_emoji_loading_indicator"));
// Populate emoji table // Populate emoji table
@ -191,97 +323,4 @@ export function set_up() {
loading_spinner: true, loading_spinner: true,
}); });
}); });
const emoji_widget = build_emoji_upload_widget();
$(".organization form.admin-emoji-form")
.off("submit")
.on("submit", function (e) {
e.preventDefault();
e.stopPropagation();
const $emoji_status = $("#admin-emoji-status");
const emoji = {};
function submit_custom_emoji_request() {
$("#admin_emoji_submit").prop("disabled", true);
const formData = new FormData();
for (const [i, file] of Array.prototype.entries.call(
$("#emoji_file_input")[0].files,
)) {
formData.append("file-" + i, file);
}
channel.post({
url: "/json/realm/emoji/" + encodeURIComponent(emoji.name),
data: formData,
cache: false,
processData: false,
contentType: false,
success() {
$("#admin-emoji-status").hide();
ui_report.success(
$t_html({defaultMessage: "Custom emoji added!"}),
$emoji_status,
);
$("form.admin-emoji-form input[type='text']").val("");
$("#admin_emoji_submit").prop("disabled", false);
emoji_widget.clear();
},
error(xhr) {
$("#admin-emoji-status").hide();
const errors = JSON.parse(xhr.responseText).msg;
xhr.responseText = JSON.stringify({msg: errors});
ui_report.error($t_html({defaultMessage: "Failed"}), xhr, $emoji_status);
$("#admin_emoji_submit").prop("disabled", false);
},
});
}
for (const obj of $(this).serializeArray()) {
emoji[obj.name] = obj.value;
}
if (emoji.name.trim() === "") {
ui_report.client_error(
$t_html({defaultMessage: "Failed: Emoji name is required."}),
$emoji_status,
);
return;
}
if (is_custom_emoji(emoji.name)) {
ui_report.client_error(
$t_html({
defaultMessage: "Failed: A custom emoji with this name already exists.",
}),
$emoji_status,
);
return;
}
if (is_default_emoji(emoji.name)) {
if (!page_params.is_admin) {
ui_report.client_error(
$t_html({
defaultMessage:
"Failed: There is a default emoji with this name. Only administrators can override default emoji.",
}),
$emoji_status,
);
return;
}
const html_body = emoji_settings_warning_modal({
emoji_name: emoji.name,
});
confirm_dialog.launch({
html_heading: $t_html({defaultMessage: "Override default emoji?"}),
html_body,
on_click: submit_custom_emoji_request,
});
} else {
submit_custom_emoji_request();
}
});
} }

View File

@ -622,17 +622,10 @@ input[type="checkbox"] {
} }
} }
.add-new-emoji-box,
.add-new-export-box {
margin-bottom: 20px;
}
.add-new-emoji-box .new-emoji-form,
.add-new-export-box { .add-new-export-box {
margin: 10px 0; margin: 10px 0;
} }
.add-new-emoji-box,
.add-new-default-stream-box { .add-new-default-stream-box {
input[type="text"] { input[type="text"] {
padding: 6px; padding: 6px;
@ -640,17 +633,30 @@ input[type="checkbox"] {
margin-bottom: 15px; margin-bottom: 15px;
} }
.add-new-emoji-box #emoji-file-name { #add-custom-emoji-modal {
width: 0; form {
top: -19px; margin: 0;
left: 3px; }
position: relative;
display: inline-block;
vertical-align: top;
input[type="text"] {
padding: 6px;
}
.emoji_name_input {
margin-top: 10px;
}
#emoji-file-name {
font-size: 14px;
white-space: nowrap; white-space: nowrap;
height: 1rem;
font-style: italic; font-style: italic;
color: hsl(0, 0%, 67%); color: hsl(0, 0%, 67%);
}
#emoji_preview_text {
margin-top: 6px;
}
} }
#emoji_file_input_error { #emoji_file_input_error {

View File

@ -0,0 +1,17 @@
<form class="new-style" id="add-custom-emoji-form">
<div>
<input type="file" name="emoji_file_input" class="notvisible"
id="emoji_file_input" value="{{t 'Upload image or GIF' }}"/>
<button class="button white rounded" style="display: none;" id="emoji_image_clear_button">{{t "Clear image" }}</button>
<button class="button rounded" id="emoji_upload_button">{{t "Upload image or GIF" }}</button>
<div style="display: none;" id="emoji_preview_text">
Preview: <i id="emoji_placeholder_icon" class="fa fa-file-image-o" aria-hidden="true"></i><img class="emoji" id="emoji_preview_image" src=""/>
</div>
<div id="emoji-file-name"></div>
</div>
<div id="emoji_file_input_error" class="text-error"></div>
<div class="emoji_name_input">
<label for="emoji_name">{{t "Emoji name" }}</label>
<input type="text" name="name" id="emoji_name" placeholder="{{t 'leafy green vegetable' }}" />
</div>
</form>

View File

@ -5,32 +5,9 @@
<p class="add-emoji-text {{#unless can_add_emojis}}hide{{/unless}}"> <p class="add-emoji-text {{#unless can_add_emojis}}hide{{/unless}}">
{{#tr}}Add extra emoji for members of the {realm_name} organization.{{/tr}} {{#tr}}Add extra emoji for members of the {realm_name} organization.{{/tr}}
</p> </p>
<form class="admin-emoji-form {{#unless can_add_emojis}}hide{{/unless}}"> <button id="add-custom-emoji-button" class="button rounded sea-green">
<div class="add-new-emoji-box grey-box"> {{t 'Add a new emoji' }}
<div class="new-emoji-form">
<div class="settings-section-title new-emoji-section-title no-padding">{{t "Add a new emoji" }}</div>
<div class="alert" id="admin-emoji-status"></div>
<div class="inline-block">
<label for="emoji_name">{{t "Emoji name" }}</label>
<input type="text" name="name" id="emoji_name" placeholder="{{t 'leafy green vegetable' }}" />
</div>
<div class="inline-block">
<span id="emoji-file-name"></span>
<input type="file" name="emoji_file_input" class="notvisible"
id="emoji_file_input" value="{{t 'Upload image or GIF' }}"/>
<button class="button white rounded" style="display: none;" id="emoji_image_clear_button">{{t "Clear emoji image" }}</button>
<button class="button rounded" id="emoji_upload_button">{{t "Upload image or GIF" }}</button>
</div>
<button id="admin_emoji_submit" type="submit" class="button rounded sea-green">
{{t 'Add emoji' }}
</button> </button>
</div>
<span id="emoji_file_input_error" class="text-error"></span>
<span style="display: none;" id="emoji_preview_text">
Preview: <img class="emoji" id="emoji_preview_image" />
</span>
</div>
</form>
<div class="settings_panel_list_header"> <div class="settings_panel_list_header">
<h3>{{t "Custom emoji"}}</h3> <h3>{{t "Custom emoji"}}</h3>