upload: Convert module to TypeScript.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2024-05-14 19:24:25 -07:00 committed by Tim Abbott
parent e74ed28f4f
commit fba81d1cd5
5 changed files with 120 additions and 64 deletions

View File

@ -261,7 +261,7 @@ EXEMPT_FILES = make_set(
"web/src/unread.ts", "web/src/unread.ts",
"web/src/unread_ops.ts", "web/src/unread_ops.ts",
"web/src/unread_ui.ts", "web/src/unread_ui.ts",
"web/src/upload.js", "web/src/upload.ts",
"web/src/upload_widget.ts", "web/src/upload_widget.ts",
"web/src/url-template.d.ts", "web/src/url-template.d.ts",
"web/src/user_card_popover.js", "web/src/user_card_popover.js",

View File

@ -74,6 +74,7 @@ export const realm_schema = z.object({
PRONOUNS: z.object({id: z.number(), name: z.string()}), PRONOUNS: z.object({id: z.number(), name: z.string()}),
}), }),
max_avatar_file_size_mib: z.number(), max_avatar_file_size_mib: z.number(),
max_file_upload_size_mib: z.number(),
max_icon_file_size_mib: z.number(), max_icon_file_size_mib: z.number(),
max_logo_file_size_mib: z.number(), max_logo_file_size_mib: z.number(),
max_message_length: z.number(), max_message_length: z.number(),

View File

@ -1,7 +1,9 @@
import type {UppyFile} from "@uppy/core";
import {Uppy} from "@uppy/core"; import {Uppy} from "@uppy/core";
import XHRUpload from "@uppy/xhr-upload"; import XHRUpload from "@uppy/xhr-upload";
import $ from "jquery"; import $ from "jquery";
import assert from "minimalistic-assert"; import assert from "minimalistic-assert";
import {z} from "zod";
import render_upload_banner from "../templates/compose_banner/upload_banner.hbs"; import render_upload_banner from "../templates/compose_banner/upload_banner.hbs";
@ -18,27 +20,42 @@ import * as message_lists from "./message_lists";
import * as rows from "./rows"; import * as rows from "./rows";
import {realm} from "./state_data"; import {realm} from "./state_data";
let drag_drop_img = null; let drag_drop_img: HTMLElement | null = null;
let compose_upload_object; let compose_upload_object: Uppy;
const upload_objects_by_message_edit_row = new Map(); const upload_objects_by_message_edit_row = new Map<number, Uppy>();
export function compose_upload_cancel() { export function compose_upload_cancel(): void {
compose_upload_object.cancelAll(); compose_upload_object.cancelAll();
} }
export function feature_check() { export function feature_check(): XMLHttpRequestUpload {
// Show the upload button only if the browser supports it. // Show the upload button only if the browser supports it.
return window.XMLHttpRequest && new window.XMLHttpRequest().upload; return window.XMLHttpRequest && new window.XMLHttpRequest().upload;
} }
export function get_translated_status(file) { export function get_translated_status(file: File | UppyFile): string {
const status = $t({defaultMessage: "Uploading {filename}…"}, {filename: file.name}); const status = $t({defaultMessage: "Uploading {filename}…"}, {filename: file.name});
return "[" + status + "]()"; return "[" + status + "]()";
} }
export const compose_config = { type Config = ({mode: "compose"} | {mode: "edit"; row: number}) & {
textarea: () => JQuery<HTMLTextAreaElement>;
send_button: () => JQuery;
banner_container: () => JQuery;
upload_banner_identifier: (file_id: string) => string;
upload_banner: (file_id: string) => JQuery;
upload_banner_cancel_button: (file_id: string) => JQuery;
upload_banner_hide_button: (file_id: string) => JQuery;
upload_banner_message: (file_id: string) => JQuery;
file_input_identifier: () => string;
source: () => string;
drag_drop_container: () => JQuery;
markdown_preview_hide_button: () => JQuery;
};
export const compose_config: Config = {
mode: "compose", mode: "compose",
textarea: () => $("textarea#compose-textarea"), textarea: () => $<HTMLTextAreaElement>("textarea#compose-textarea"),
send_button: () => $("#compose-send-button"), send_button: () => $("#compose-send-button"),
banner_container: () => $("#compose_banners"), banner_container: () => $("#compose_banners"),
upload_banner_identifier: (file_id) => upload_banner_identifier: (file_id) =>
@ -58,55 +75,58 @@ export const compose_config = {
), ),
upload_banner_message: (file_id) => upload_banner_message: (file_id) =>
$(`#compose_banners .upload_banner.file_${CSS.escape(file_id)} .upload_msg`), $(`#compose_banners .upload_banner.file_${CSS.escape(file_id)} .upload_msg`),
file_input_identifier: () => "#compose .file_input", file_input_identifier: () => "#compose input.file_input",
source: () => "compose-file-input", source: () => "compose-file-input",
drag_drop_container: () => $("#compose"), drag_drop_container: () => $("#compose"),
markdown_preview_hide_button: () => $("#compose .undo_markdown_preview"), markdown_preview_hide_button: () => $("#compose .undo_markdown_preview"),
}; };
export function edit_config(row) { export function edit_config(row: number): Config {
return { return {
mode: "edit", mode: "edit",
row, row,
textarea: () => $(`#edit_form_${CSS.escape(row)} .message_edit_content`), textarea: () =>
send_button: () => $(`#edit_form_${CSS.escape(row)}`).find(".message_edit_save"), $<HTMLTextAreaElement>(
banner_container: () => $(`#edit_form_${CSS.escape(row)} .edit_form_banners`), `#edit_form_${CSS.escape(`${row}`)} textarea.message_edit_content`,
),
send_button: () => $(`#edit_form_${CSS.escape(`${row}`)}`).find(".message_edit_save"),
banner_container: () => $(`#edit_form_${CSS.escape(`${row}`)} .edit_form_banners`),
upload_banner_identifier: (file_id) => upload_banner_identifier: (file_id) =>
`#edit_form_${CSS.escape(row)} .upload_banner.file_${CSS.escape(file_id)}`, `#edit_form_${CSS.escape(`${row}`)} .upload_banner.file_${CSS.escape(file_id)}`,
upload_banner: (file_id) => upload_banner: (file_id) =>
$(`#edit_form_${CSS.escape(row)} .upload_banner.file_${CSS.escape(file_id)}`), $(`#edit_form_${CSS.escape(`${row}`)} .upload_banner.file_${CSS.escape(file_id)}`),
upload_banner_cancel_button: (file_id) => upload_banner_cancel_button: (file_id) =>
$( $(
`#edit_form_${CSS.escape(row)} .upload_banner.file_${CSS.escape( `#edit_form_${CSS.escape(`${row}`)} .upload_banner.file_${CSS.escape(
file_id, file_id,
)} .upload_banner_cancel_button`, )} .upload_banner_cancel_button`,
), ),
upload_banner_hide_button: (file_id) => upload_banner_hide_button: (file_id) =>
$( $(
`#edit_form_${CSS.escape(row)} .upload_banner.file_${CSS.escape( `#edit_form_${CSS.escape(`${row}`)} .upload_banner.file_${CSS.escape(
file_id, file_id,
)} .main-view-banner-close-button`, )} .main-view-banner-close-button`,
), ),
upload_banner_message: (file_id) => upload_banner_message: (file_id) =>
$( $(
`#edit_form_${CSS.escape(row)} .upload_banner.file_${CSS.escape( `#edit_form_${CSS.escape(`${row}`)} .upload_banner.file_${CSS.escape(
file_id, file_id,
)} .upload_msg`, )} .upload_msg`,
), ),
file_input_identifier: () => `#edit_form_${CSS.escape(row)} .file_input`, file_input_identifier: () => `#edit_form_${CSS.escape(`${row}`)} input.file_input`,
source: () => "message-edit-file-input", source: () => "message-edit-file-input",
drag_drop_container() { drag_drop_container() {
assert(message_lists.current !== undefined); assert(message_lists.current !== undefined);
return $( return $(
`#message-row-${message_lists.current.id}-${CSS.escape(row)} .message_edit_form`, `#message-row-${message_lists.current.id}-${CSS.escape(`${row}`)} .message_edit_form`,
); );
}, },
markdown_preview_hide_button: () => markdown_preview_hide_button: () =>
$(`#edit_form_${CSS.escape(row)} .undo_markdown_preview`), $(`#edit_form_${CSS.escape(`${row}`)} .undo_markdown_preview`),
}; };
} }
export function hide_upload_banner(uppy, config, file_id) { export function hide_upload_banner(uppy: Uppy, config: Config, file_id: string): void {
config.upload_banner(file_id).remove(); config.upload_banner(file_id).remove();
if (uppy.getFiles().length === 0) { if (uppy.getFiles().length === 0) {
if (config.mode === "compose") { if (config.mode === "compose") {
@ -118,12 +138,12 @@ export function hide_upload_banner(uppy, config, file_id) {
} }
function add_upload_banner( function add_upload_banner(
config, config: Config,
banner_type, banner_type: string,
banner_text, banner_text: string,
file_id, file_id: string,
is_upload_process_tracker = false, is_upload_process_tracker = false,
) { ): void {
const new_banner_html = render_upload_banner({ const new_banner_html = render_upload_banner({
banner_type, banner_type,
is_upload_process_tracker, is_upload_process_tracker,
@ -137,10 +157,10 @@ function add_upload_banner(
} }
export function show_error_message( export function show_error_message(
config, config: Config,
message = $t({defaultMessage: "An unknown error occurred."}), message = $t({defaultMessage: "An unknown error occurred."}),
file_id = null, file_id: string | null = null,
) { ): void {
if (file_id) { if (file_id) {
$(`${config.upload_banner_identifier(file_id)} .moving_bar`).hide(); $(`${config.upload_banner_identifier(file_id)} .moving_bar`).hide();
config.upload_banner(file_id).removeClass("info").addClass("error"); config.upload_banner(file_id).removeClass("info").addClass("error");
@ -153,7 +173,7 @@ export function show_error_message(
} }
} }
export async function upload_files(uppy, config, files) { export function upload_files(uppy: Uppy, config: Config, files: File[] | FileList): void {
if (files.length === 0) { if (files.length === 0) {
return; return;
} }
@ -179,6 +199,7 @@ export async function upload_files(uppy, config, files) {
} }
for (const file of files) { for (const file of files) {
let file_id;
try { try {
compose_ui.insert_syntax_and_focus( compose_ui.insert_syntax_and_focus(
get_translated_status(file), get_translated_status(file),
@ -187,7 +208,7 @@ export async function upload_files(uppy, config, files) {
1, 1,
); );
compose_ui.autosize_textarea(config.textarea()); compose_ui.autosize_textarea(config.textarea());
file.id = uppy.addFile({ file_id = uppy.addFile({
source: config.source(), source: config.source(),
name: file.name, name: file.name,
type: file.type, type: file.type,
@ -207,24 +228,24 @@ export async function upload_files(uppy, config, files) {
config, config,
"info", "info",
$t({defaultMessage: "Uploading {filename}…"}, {filename: file.name}), $t({defaultMessage: "Uploading {filename}…"}, {filename: file.name}),
file.id, file_id,
true, true,
); );
config.upload_banner_cancel_button(file.id).one("click", () => { config.upload_banner_cancel_button(file_id).one("click", () => {
compose_ui.replace_syntax(get_translated_status(file), "", config.textarea()); compose_ui.replace_syntax(get_translated_status(file), "", config.textarea());
compose_ui.autosize_textarea(config.textarea()); compose_ui.autosize_textarea(config.textarea());
config.textarea().trigger("focus"); config.textarea().trigger("focus");
uppy.removeFile(file.id); uppy.removeFile(file_id);
hide_upload_banner(uppy, config, file.id); hide_upload_banner(uppy, config, file_id);
}); });
config.upload_banner_hide_button(file.id).one("click", () => { config.upload_banner_hide_button(file_id).one("click", () => {
hide_upload_banner(uppy, config, file.id); hide_upload_banner(uppy, config, file_id);
}); });
} }
} }
export function setup_upload(config) { export function setup_upload(config: Config): Uppy {
const uppy = new Uppy({ const uppy = new Uppy({
debug: false, debug: false,
autoProceed: true, autoProceed: true,
@ -267,14 +288,16 @@ export function setup_upload(config) {
} }
uppy.on("upload-progress", (file, progress) => { uppy.on("upload-progress", (file, progress) => {
assert(file !== undefined);
const percent_complete = (100 * progress.bytesUploaded) / progress.bytesTotal; const percent_complete = (100 * progress.bytesUploaded) / progress.bytesTotal;
$(`${config.upload_banner_identifier(file.id)} .moving_bar`).css({ $(`${config.upload_banner_identifier(file.id)} .moving_bar`).css({
width: `${percent_complete}%`, width: `${percent_complete}%`,
}); });
}); });
$(config.file_input_identifier()).on("change", (event) => { $<HTMLInputElement>(config.file_input_identifier()).on("change", (event) => {
const files = event.target.files; const files = event.target.files;
assert(files !== null);
upload_files(uppy, config, files); upload_files(uppy, config, files);
config.textarea().trigger("focus"); config.textarea().trigger("focus");
event.target.value = ""; event.target.value = "";
@ -291,12 +314,18 @@ export function setup_upload(config) {
); );
const $drag_drop_container = config.drag_drop_container(); const $drag_drop_container = config.drag_drop_container();
$drag_drop_container.on("dragover", (event) => event.preventDefault()); $drag_drop_container.on("dragover", (event) => {
$drag_drop_container.on("dragenter", (event) => event.preventDefault()); event.preventDefault();
});
$drag_drop_container.on("dragenter", (event) => {
event.preventDefault();
});
$drag_drop_container.on("drop", (event) => { $drag_drop_container.on("drop", (event) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
assert(event.originalEvent !== undefined);
assert(event.originalEvent.dataTransfer !== null);
const files = event.originalEvent.dataTransfer.files; const files = event.originalEvent.dataTransfer.files;
if (config.mode === "compose" && !compose_state.composing()) { if (config.mode === "compose" && !compose_state.composing()) {
compose_reply.respond_to_message({ compose_reply.respond_to_message({
@ -308,17 +337,18 @@ export function setup_upload(config) {
}); });
$drag_drop_container.on("paste", (event) => { $drag_drop_container.on("paste", (event) => {
const clipboard_data = event.clipboardData || event.originalEvent.clipboardData; assert(event.originalEvent instanceof ClipboardEvent);
const clipboard_data = event.originalEvent.clipboardData;
if (!clipboard_data) { if (!clipboard_data) {
return; return;
} }
const items = clipboard_data.items; const items = clipboard_data.items;
const files = []; const files = [];
for (const item of items) { for (const item of items) {
if (item.kind !== "file") { const file = item.getAsFile();
if (file === null) {
continue; continue;
} }
const file = item.getAsFile();
files.push(file); files.push(file);
} }
if (files.length === 0) { if (files.length === 0) {
@ -338,7 +368,8 @@ export function setup_upload(config) {
}); });
uppy.on("upload-success", (file, response) => { uppy.on("upload-success", (file, response) => {
const url = response.body.uri; assert(file !== undefined);
const {uri: url} = z.object({uri: z.string().optional()}).parse(response.body);
if (url === undefined) { if (url === undefined) {
return; return;
} }
@ -376,7 +407,9 @@ export function setup_upload(config) {
// TODO: Ideally, we'd be using the `.error()` hook or // TODO: Ideally, we'd be using the `.error()` hook or
// something, not parsing error message strings. // something, not parsing error message strings.
const infoList = uppy.getState().info; const infoList = uppy.getState().info;
assert(infoList !== undefined);
const info = infoList.at(-1); const info = infoList.at(-1);
assert(info !== undefined);
if (info.type === "error" && info.message === "No Internet connection") { if (info.type === "error" && info.message === "No Internet connection") {
// server_events already handles the case of no internet. // server_events already handles the case of no internet.
return; return;
@ -397,11 +430,17 @@ export function setup_upload(config) {
}); });
uppy.on("upload-error", (file, _error, response) => { uppy.on("upload-error", (file, _error, response) => {
assert(file !== undefined);
// The files with failed upload should be removed since uppy doesn't allow files in the store // The files with failed upload should be removed since uppy doesn't allow files in the store
// to be re-uploaded again. // to be re-uploaded again.
uppy.removeFile(file.id); uppy.removeFile(file.id);
const message = response ? response.body.msg : undefined; let parsed;
const message =
response !== undefined &&
(parsed = z.object({msg: z.string()}).safeParse(response.body)).success
? parsed.data.msg
: undefined;
// Hide the upload status banner on error so only the error banner shows // Hide the upload status banner on error so only the error banner shows
hide_upload_banner(uppy, config, file.id); hide_upload_banner(uppy, config, file.id);
show_error_message(config, message, file.id); show_error_message(config, message, file.id);
@ -410,6 +449,7 @@ export function setup_upload(config) {
}); });
uppy.on("restriction-failed", (file) => { uppy.on("restriction-failed", (file) => {
assert(file !== undefined);
compose_ui.replace_syntax(get_translated_status(file), "", config.textarea()); compose_ui.replace_syntax(get_translated_status(file), "", config.textarea());
compose_ui.autosize_textarea(config.textarea()); compose_ui.autosize_textarea(config.textarea());
}); });
@ -417,7 +457,7 @@ export function setup_upload(config) {
return uppy; return uppy;
} }
export function deactivate_upload(config) { export function deactivate_upload(config: Config): void {
// Remove event listeners added for handling uploads. // Remove event listeners added for handling uploads.
$(config.file_input_identifier()).off("change"); $(config.file_input_identifier()).off("change");
config.banner_container().off("click"); config.banner_container().off("click");
@ -451,7 +491,7 @@ export function deactivate_upload(config) {
} }
} }
export function initialize() { export function initialize(): void {
compose_upload_object = setup_upload(compose_config); compose_upload_object = setup_upload(compose_config);
$(".app, #navbar-fixed-container").on("dragstart", (event) => { $(".app, #navbar-fixed-container").on("dragstart", (event) => {
@ -463,10 +503,14 @@ export function initialize() {
}); });
// Allow the app panel to receive drag/drop events. // Allow the app panel to receive drag/drop events.
$(".app, #navbar-fixed-container").on("dragover", (event) => event.preventDefault()); $(".app, #navbar-fixed-container").on("dragover", (event) => {
event.preventDefault();
});
// TODO: Do something visual to hint that drag/drop will work. // TODO: Do something visual to hint that drag/drop will work.
$(".app, #navbar-fixed-container").on("dragenter", (event) => event.preventDefault()); $(".app, #navbar-fixed-container").on("dragenter", (event) => {
event.preventDefault();
});
$(".app, #navbar-fixed-container").on("drop", (event) => { $(".app, #navbar-fixed-container").on("drop", (event) => {
event.preventDefault(); event.preventDefault();
@ -477,6 +521,8 @@ export function initialize() {
} }
const $drag_drop_edit_containers = $(".message_edit_form form"); const $drag_drop_edit_containers = $(".message_edit_form form");
assert(event.originalEvent !== undefined);
assert(event.originalEvent.dataTransfer !== null);
const files = event.originalEvent.dataTransfer.files; const files = event.originalEvent.dataTransfer.files;
const $last_drag_drop_edit_container = $drag_drop_edit_containers.last(); const $last_drag_drop_edit_container = $drag_drop_edit_containers.last();
@ -496,6 +542,7 @@ export function initialize() {
return; return;
} }
const edit_upload_object = upload_objects_by_message_edit_row.get(row_id); const edit_upload_object = upload_objects_by_message_edit_row.get(row_id);
assert(edit_upload_object !== undefined);
upload_files(edit_upload_object, edit_config(row_id), files); upload_files(edit_upload_object, edit_config(row_id), files);
} else if (message_lists.current?.selected_message()) { } else if (message_lists.current?.selected_message()) {

View File

@ -10,8 +10,8 @@ const blueslip_stacktrace = zrequire("blueslip_stacktrace");
run_test("clean_path", () => { run_test("clean_path", () => {
// Local file // Local file
assert.strictEqual( assert.strictEqual(
blueslip_stacktrace.clean_path("webpack:///web/src/upload.js"), blueslip_stacktrace.clean_path("webpack:///web/src/upload.ts"),
"/web/src/upload.js", "/web/src/upload.ts",
); );
// Third party library (jQuery) // Third party library (jQuery)
@ -36,9 +36,9 @@ run_test("clean_function_name", () => {
// Local file // Local file
assert.deepEqual( assert.deepEqual(
blueslip_stacktrace.clean_function_name("Object../web/src/upload.js.exports.options"), blueslip_stacktrace.clean_function_name("Object../web/src/upload.ts.exports.options"),
{ {
scope: "Object../web/src/upload.js.exports.", scope: "Object../web/src/upload.ts.exports.",
name: "options", name: "options",
}, },
); );

View File

@ -7,6 +7,13 @@ const {run_test, noop} = require("./lib/test");
const $ = require("./lib/zjquery"); const $ = require("./lib/zjquery");
const {realm} = require("./lib/zpage_params"); const {realm} = require("./lib/zpage_params");
class ClipboardEvent {
constructor({clipboardData}) {
this.clipboardData = clipboardData;
}
}
set_global("ClipboardEvent", ClipboardEvent);
set_global("navigator", { set_global("navigator", {
userAgent: "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)", userAgent: "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)",
}); });
@ -60,7 +67,7 @@ test("config", () => {
upload.compose_config.upload_banner_hide_button("id_2"), upload.compose_config.upload_banner_hide_button("id_2"),
$("#compose_banners .upload_banner.file_id_2 .main-view-banner-close-button"), $("#compose_banners .upload_banner.file_id_2 .main-view-banner-close-button"),
); );
assert.equal(upload.compose_config.file_input_identifier(), "#compose .file_input"); assert.equal(upload.compose_config.file_input_identifier(), "#compose input.file_input");
assert.equal(upload.compose_config.source(), "compose-file-input"); assert.equal(upload.compose_config.source(), "compose-file-input");
assert.equal(upload.compose_config.drag_drop_container(), $("#compose")); assert.equal(upload.compose_config.drag_drop_container(), $("#compose"));
assert.equal( assert.equal(
@ -70,7 +77,7 @@ test("config", () => {
assert.equal( assert.equal(
upload.edit_config(1).textarea(), upload.edit_config(1).textarea(),
$(`#edit_form_${CSS.escape(1)} .message_edit_content`), $(`#edit_form_${CSS.escape(1)} textarea.message_edit_content`),
); );
$(`#edit_form_${CSS.escape(2)}`).set_find_results( $(`#edit_form_${CSS.escape(2)}`).set_find_results(
@ -117,7 +124,7 @@ test("config", () => {
assert.equal( assert.equal(
upload.edit_config(123).file_input_identifier(), upload.edit_config(123).file_input_identifier(),
`#edit_form_${CSS.escape(123)} .file_input`, `#edit_form_${CSS.escape(123)} input.file_input`,
); );
assert.equal(upload.edit_config(123).source(), "message-edit-file-input"); assert.equal(upload.edit_config(123).source(), "message-edit-file-input");
assert.equal( assert.equal(
@ -343,7 +350,7 @@ test("uppy_config", () => {
test("file_input", ({override_rewire}) => { test("file_input", ({override_rewire}) => {
upload.setup_upload(upload.compose_config); upload.setup_upload(upload.compose_config);
const change_handler = $("#compose .file_input").get_on_handler("change"); const change_handler = $("#compose input.file_input").get_on_handler("change");
const files = ["file1", "file2"]; const files = ["file1", "file2"];
const event = { const event = {
target: { target: {
@ -417,7 +424,7 @@ test("copy_paste", ({override, override_rewire}) => {
const paste_handler = $("#compose").get_on_handler("paste"); const paste_handler = $("#compose").get_on_handler("paste");
let get_as_file_called = false; let get_as_file_called = false;
let event = { let event = {
originalEvent: { originalEvent: new ClipboardEvent({
clipboardData: { clipboardData: {
items: [ items: [
{ {
@ -428,10 +435,11 @@ test("copy_paste", ({override, override_rewire}) => {
}, },
{ {
kind: "notfile", kind: "notfile",
getAsFile: () => null,
}, },
], ],
}, },
}, }),
preventDefault() {}, preventDefault() {},
}; };
let upload_files_called = false; let upload_files_called = false;
@ -449,7 +457,7 @@ test("copy_paste", ({override, override_rewire}) => {
assert.ok(compose_actions_start_called); assert.ok(compose_actions_start_called);
upload_files_called = false; upload_files_called = false;
event = { event = {
originalEvent: {}, originalEvent: new ClipboardEvent({}),
}; };
paste_handler(event); paste_handler(event);
assert.equal(upload_files_called, false); assert.equal(upload_files_called, false);
@ -585,7 +593,7 @@ test("uppy_events", ({override_rewire, mock_template}) => {
assert.ok(compose_ui_replace_syntax_called); assert.ok(compose_ui_replace_syntax_called);
compose_ui_replace_syntax_called = false; compose_ui_replace_syntax_called = false;
on_upload_error_callback(file, null, null); on_upload_error_callback(file, null, undefined);
assert.ok(compose_ui_replace_syntax_called); assert.ok(compose_ui_replace_syntax_called);
$("#compose_banners .upload_banner .upload_msg").text(""); $("#compose_banners .upload_banner .upload_msg").text("");