mirror of https://github.com/zulip/zulip.git
parent
df001db1a9
commit
b7335d0dec
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue