diff --git a/frontend_tests/node_tests/settings_emoji.js b/frontend_tests/node_tests/settings_emoji.js index e9c4ee22f1..387ecc4b77 100644 --- a/frontend_tests/node_tests/settings_emoji.js +++ b/frontend_tests/node_tests/settings_emoji.js @@ -9,7 +9,7 @@ const $ = require("../zjsunit/zjquery"); const upload_widget = mock_esm("../../static/js/upload_widget"); const settings_emoji = zrequire("settings_emoji"); -run_test("build_emoji_upload_widget", () => { +run_test("add_custom_emoji_post_render", () => { let build_widget_stub = false; upload_widget.build_widget = ( get_file_input, @@ -25,6 +25,6 @@ run_test("build_emoji_upload_widget", () => { assert.deepEqual(upload_button, $("#emoji_upload_button")); build_widget_stub = true; }; - settings_emoji.build_emoji_upload_widget(); + settings_emoji.add_custom_emoji_post_render(); assert.ok(build_widget_stub); }); diff --git a/frontend_tests/puppeteer_tests/admin.ts b/frontend_tests/puppeteer_tests/admin.ts index 316ccb618a..85fa12e490 100644 --- a/frontend_tests/puppeteer_tests/admin.ts +++ b/frontend_tests/puppeteer_tests/admin.ts @@ -179,21 +179,15 @@ async function test_organization_permissions(page: Page): Promise { } async function test_add_emoji(page: Page): Promise { - 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"); assert.ok(emoji_upload_handle); await (emoji_upload_handle as ElementHandle).uploadFile( "static/images/logo/zulip-icon-128x128.png", ); - await page.click("#admin_emoji_submit"); - - 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.click("#add-custom-emoji-modal .dialog_submit_button"); + await common.wait_for_micromodal_to_close(page); await page.waitForSelector("tr#emoji_zulip_logo", {visible: true}); assert.strictEqual( @@ -217,7 +211,8 @@ async function test_delete_emoji(page: Page): Promise { async function test_custom_realm_emoji(page: Page): Promise { 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_delete_emoji(page); diff --git a/static/js/settings_emoji.js b/static/js/settings_emoji.js index bc5aa02891..e6bee088c6 100644 --- a/static/js/settings_emoji.js +++ b/static/js/settings_emoji.js @@ -3,6 +3,7 @@ import $ from "jquery"; 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 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_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); if (!settings_data.user_can_add_custom_emoji()) { $(".add-emoji-text").hide(); - $(".admin-emoji-form").hide(); + $("#add-custom-emoji-button").hide(); } else { $(".add-emoji-text").show(); - $(".admin-emoji-form").show(); + $("#add-custom-emoji-button").show(); } populate_emoji(); @@ -138,7 +139,16 @@ export function populate_emoji() { 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 () { return $("#emoji_file_input"); }; @@ -149,8 +159,11 @@ export function build_emoji_upload_widget() { const $upload_button = $("#emoji_upload_button"); const $preview_text = $("#emoji_preview_text"); 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, $file_name_field, $input_error, @@ -159,11 +172,130 @@ export function build_emoji_upload_widget() { $preview_text, $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() { meta.loaded = true; + $("#add-custom-emoji-button").on("click", show_modal); + loading.make_indicator($("#admin_page_emoji_loading_indicator")); // Populate emoji table @@ -191,97 +323,4 @@ export function set_up() { 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(); - } - }); } diff --git a/static/styles/settings.css b/static/styles/settings.css index df84eaf10a..9596116095 100644 --- a/static/styles/settings.css +++ b/static/styles/settings.css @@ -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 { margin: 10px 0; } -.add-new-emoji-box, .add-new-default-stream-box { input[type="text"] { padding: 6px; @@ -640,17 +633,30 @@ input[type="checkbox"] { margin-bottom: 15px; } -.add-new-emoji-box #emoji-file-name { - width: 0; - top: -19px; - left: 3px; - position: relative; - display: inline-block; - vertical-align: top; +#add-custom-emoji-modal { + form { + margin: 0; + } - white-space: nowrap; - font-style: italic; - color: hsl(0, 0%, 67%); + input[type="text"] { + padding: 6px; + } + + .emoji_name_input { + margin-top: 10px; + } + + #emoji-file-name { + font-size: 14px; + white-space: nowrap; + height: 1rem; + font-style: italic; + color: hsl(0, 0%, 67%); + } + + #emoji_preview_text { + margin-top: 6px; + } } #emoji_file_input_error { diff --git a/static/templates/settings/add_emoji.hbs b/static/templates/settings/add_emoji.hbs new file mode 100644 index 0000000000..60aaf49bf0 --- /dev/null +++ b/static/templates/settings/add_emoji.hbs @@ -0,0 +1,17 @@ +
+
+ + + + +
+
+
+
+ + +
+
diff --git a/static/templates/settings/emoji_settings_admin.hbs b/static/templates/settings/emoji_settings_admin.hbs index 1eda96261c..a7bb177279 100644 --- a/static/templates/settings/emoji_settings_admin.hbs +++ b/static/templates/settings/emoji_settings_admin.hbs @@ -5,32 +5,9 @@

{{#tr}}Add extra emoji for members of the {realm_name} organization.{{/tr}}

-
-
-
-
{{t "Add a new emoji" }}
-
-
- - -
-
- - - - -
- -
- - -
-
+

{{t "Custom emoji"}}