2017-11-23 15:00:05 +01:00
|
|
|
function make_upload_absolute(uri) {
|
|
|
|
if (uri.indexOf(compose.uploads_path) === 0) {
|
|
|
|
// Rewrite the URI to a usable link
|
|
|
|
return compose.uploads_domain + uri;
|
|
|
|
}
|
|
|
|
return uri;
|
|
|
|
}
|
|
|
|
|
2018-02-13 23:26:19 +01:00
|
|
|
// Show the upload button only if the browser supports it.
|
|
|
|
exports.feature_check = function (upload_button) {
|
2019-11-09 02:48:01 +01:00
|
|
|
if (window.XMLHttpRequest && new XMLHttpRequest().upload) {
|
2018-02-13 23:26:19 +01:00
|
|
|
upload_button.removeClass("notdisplayed");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-02-13 22:48:48 +01:00
|
|
|
exports.options = function (config) {
|
2019-11-02 00:06:25 +01:00
|
|
|
let textarea;
|
|
|
|
let send_button;
|
|
|
|
let send_status;
|
|
|
|
let send_status_close;
|
|
|
|
let error_msg;
|
|
|
|
let upload_bar;
|
|
|
|
let file_input;
|
2018-02-13 22:48:48 +01:00
|
|
|
|
|
|
|
switch (config.mode) {
|
|
|
|
case 'compose':
|
|
|
|
textarea = $('#compose-textarea');
|
|
|
|
send_button = $('#compose-send-button');
|
|
|
|
send_status = $('#compose-send-status');
|
|
|
|
send_status_close = $('.compose-send-status-close');
|
|
|
|
error_msg = $('#compose-error-msg');
|
|
|
|
upload_bar = 'compose-upload-bar';
|
|
|
|
file_input = 'file_input';
|
|
|
|
break;
|
2017-11-28 22:36:58 +01:00
|
|
|
case 'edit':
|
|
|
|
textarea = $('#message_edit_content_' + config.row);
|
2019-04-16 03:34:54 +02:00
|
|
|
send_button = textarea.closest('#message_edit_form').find('.message_edit_save');
|
2017-11-28 22:36:58 +01:00
|
|
|
send_status = $('#message-edit-send-status-' + config.row);
|
|
|
|
send_status_close = send_status.find('.send-status-close');
|
|
|
|
error_msg = send_status.find('.error-msg');
|
|
|
|
upload_bar = 'message-edit-upload-bar-' + config.row;
|
|
|
|
file_input = 'message_edit_file_input_' + config.row;
|
|
|
|
break;
|
2018-02-13 22:48:48 +01:00
|
|
|
default:
|
|
|
|
throw Error("Invalid upload mode!");
|
|
|
|
}
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const hide_upload_status = function () {
|
2018-04-16 21:33:48 +02:00
|
|
|
send_button.prop("disabled", false);
|
|
|
|
send_status.removeClass("alert-info").hide();
|
2018-04-14 11:48:22 +02:00
|
|
|
$('div.progress.active').remove();
|
2018-04-05 04:29:21 +02:00
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const drop = function () {
|
2018-02-13 22:48:48 +01:00
|
|
|
send_button.attr("disabled", "");
|
|
|
|
send_status.addClass("alert-info").show();
|
2018-04-13 20:49:41 +02:00
|
|
|
send_status_close.one('click', function () {
|
2018-04-16 21:33:48 +02:00
|
|
|
setTimeout(function () {
|
|
|
|
hide_upload_status();
|
|
|
|
}, 500);
|
2018-04-13 20:49:41 +02:00
|
|
|
compose.abort_xhr();
|
|
|
|
});
|
2018-04-14 11:48:22 +02:00
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const uploadStarted = function (i, file) {
|
2018-04-05 04:29:21 +02:00
|
|
|
error_msg.html($("<p>").text(i18n.t("Uploading…")));
|
2019-04-29 07:51:17 +02:00
|
|
|
// file.lastModified is unique for each upload, and was previously used to track each
|
|
|
|
// upload. But, when an image is pasted into Safari, it looks like the lastModified time
|
|
|
|
// gets changed by the time the image upload is finished, and we lose track of the
|
|
|
|
// uploaded images. Instead, we set a random ID for each image, to track it.
|
|
|
|
if (!file.trackingId) { // The conditional check is present to make this easy to test
|
|
|
|
file.trackingId = Math.random().toString().substring(2); // Use digits after the `.`
|
|
|
|
}
|
2018-04-10 23:36:07 +02:00
|
|
|
send_status.append('<div class="progress active">' +
|
2019-04-29 07:51:17 +02:00
|
|
|
'<div class="bar" id="' + upload_bar + '-' + file.trackingId + '" style="width: 0"></div>' +
|
2018-04-05 04:29:21 +02:00
|
|
|
'</div>');
|
2018-08-15 03:57:35 +02:00
|
|
|
compose_ui.insert_syntax_and_focus("[Uploading " + file.name + "…]()", textarea);
|
2018-02-13 22:39:51 +01:00
|
|
|
};
|
2017-11-23 15:00:05 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const progressUpdated = function (i, file, progress) {
|
2019-04-29 07:51:17 +02:00
|
|
|
$("#" + upload_bar + '-' + file.trackingId).width(progress + "%");
|
2018-02-13 22:39:51 +01:00
|
|
|
};
|
2017-11-23 15:00:05 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const uploadError = function (error_code, server_response, file) {
|
|
|
|
let msg;
|
2018-04-14 11:48:22 +02:00
|
|
|
send_status.addClass("alert-error").removeClass("alert-info");
|
2018-02-13 22:48:48 +01:00
|
|
|
send_button.prop("disabled", false);
|
2018-04-14 11:48:22 +02:00
|
|
|
if (file !== undefined) {
|
2019-04-29 07:51:17 +02:00
|
|
|
$("#" + upload_bar + '-' + file.trackingId).parent().remove();
|
2018-04-14 11:48:22 +02:00
|
|
|
}
|
|
|
|
|
2018-02-13 22:39:51 +01:00
|
|
|
switch (error_code) {
|
2017-11-23 15:00:05 +01:00
|
|
|
case 'BrowserNotSupported':
|
|
|
|
msg = i18n.t("File upload is not yet available for your browser.");
|
|
|
|
break;
|
|
|
|
case 'TooManyFiles':
|
|
|
|
msg = i18n.t("Unable to upload that many files at once.");
|
|
|
|
break;
|
|
|
|
case 'FileTooLarge':
|
2019-05-04 20:24:36 +02:00
|
|
|
if (page_params.max_file_upload_size > 0) {
|
|
|
|
// sanitization not needed as the file name is not potentially parsed as HTML, etc.
|
2019-11-02 00:06:25 +01:00
|
|
|
const context = {
|
2019-05-04 20:24:36 +02:00
|
|
|
file_name: file.name,
|
|
|
|
file_size: page_params.max_file_upload_size,
|
|
|
|
};
|
|
|
|
msg = i18n.t('"__file_name__" was too large; the maximum file size is __file_size__MB.',
|
|
|
|
context);
|
|
|
|
} else {
|
|
|
|
// If uploading files has been disabled.
|
|
|
|
msg = i18n.t('File and image uploads have been disabled for this organization.');
|
|
|
|
}
|
2017-11-23 15:00:05 +01:00
|
|
|
break;
|
2018-01-27 03:50:37 +01:00
|
|
|
case 413: // HTTP status "Request Entity Too Large"
|
2017-11-23 15:00:05 +01:00
|
|
|
msg = i18n.t("Sorry, the file was too large.");
|
|
|
|
break;
|
2019-10-25 23:55:37 +02:00
|
|
|
case 400: {
|
2019-11-02 00:06:25 +01:00
|
|
|
const server_message = server_response && server_response.msg;
|
2018-01-27 04:00:32 +01:00
|
|
|
msg = server_message || i18n.t("An unknown error occurred.");
|
|
|
|
break;
|
2019-10-25 23:55:37 +02:00
|
|
|
}
|
2017-11-23 15:00:05 +01:00
|
|
|
default:
|
|
|
|
msg = i18n.t("An unknown error occurred.");
|
|
|
|
break;
|
2018-02-13 22:39:51 +01:00
|
|
|
}
|
2018-02-13 22:48:48 +01:00
|
|
|
error_msg.text(msg);
|
2018-02-13 22:39:51 +01:00
|
|
|
};
|
2017-11-23 15:00:05 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const uploadFinished = function (i, file, response) {
|
2018-02-13 22:39:51 +01:00
|
|
|
if (response.uri === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
2019-11-02 00:06:25 +01:00
|
|
|
const split_uri = response.uri.split("/");
|
|
|
|
const filename = split_uri[split_uri.length - 1];
|
2018-02-13 22:39:51 +01:00
|
|
|
// Urgh, yet another hack to make sure we're "composing"
|
|
|
|
// when text gets added into the composebox.
|
2019-02-08 11:16:59 +01:00
|
|
|
if (config.mode === 'compose' && !compose_state.composing()) {
|
2018-02-13 22:39:51 +01:00
|
|
|
compose_actions.start('stream');
|
2019-02-08 11:16:59 +01:00
|
|
|
} else if (config.mode === 'edit' && document.activeElement !== textarea) {
|
|
|
|
// If we are editing, focus on the edit message box
|
|
|
|
textarea.focus();
|
2018-02-13 22:39:51 +01:00
|
|
|
}
|
2017-11-23 15:00:05 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const uri = make_upload_absolute(response.uri);
|
2017-11-23 15:00:05 +01:00
|
|
|
|
2018-02-13 22:39:51 +01:00
|
|
|
if (i === -1) {
|
|
|
|
// This is a paste, so there's no filename. Show the image directly
|
2019-11-02 00:06:25 +01:00
|
|
|
const pasted_image_uri = "[pasted image](" + uri + ")";
|
2018-08-15 03:57:35 +02:00
|
|
|
compose_ui.replace_syntax("[Uploading " + file.name + "…]()", pasted_image_uri, textarea);
|
2018-02-13 22:39:51 +01:00
|
|
|
} else {
|
|
|
|
// This is a dropped file, so make the filename a link to the image
|
2019-11-02 00:06:25 +01:00
|
|
|
const filename_uri = "[" + filename + "](" + uri + ")";
|
2018-08-15 03:57:35 +02:00
|
|
|
compose_ui.replace_syntax("[Uploading " + file.name + "…]()", filename_uri, textarea);
|
2018-02-13 22:39:51 +01:00
|
|
|
}
|
|
|
|
compose_ui.autosize_textarea();
|
2018-04-05 04:29:21 +02:00
|
|
|
|
2018-04-16 21:33:48 +02:00
|
|
|
setTimeout(function () {
|
2019-04-29 07:51:17 +02:00
|
|
|
$("#" + upload_bar + '-' + file.trackingId).parent().remove();
|
2018-04-16 21:33:48 +02:00
|
|
|
if ($('div.progress.active').length === 0) {
|
|
|
|
hide_upload_status(file);
|
|
|
|
}
|
|
|
|
}, 500);
|
2017-11-23 15:00:05 +01:00
|
|
|
|
2018-02-13 22:39:51 +01:00
|
|
|
// In order to upload the same file twice in a row, we need to clear out
|
2018-02-13 23:29:17 +01:00
|
|
|
// the file input element, so that the next time we use the file dialog,
|
|
|
|
// an actual change event is fired. IE doesn't allow .val('') so we
|
|
|
|
// need to clone it. (Taken from the jQuery form plugin)
|
|
|
|
if (/MSIE/.test(navigator.userAgent)) {
|
|
|
|
$('#' + file_input).replaceWith($('#' + file_input).clone(true));
|
|
|
|
} else {
|
|
|
|
$('#' + file_input).val('');
|
|
|
|
}
|
2018-02-13 22:39:51 +01:00
|
|
|
};
|
2017-11-23 15:00:05 +01:00
|
|
|
|
2018-02-13 22:39:51 +01:00
|
|
|
return {
|
2017-11-23 15:00:05 +01:00
|
|
|
url: "/json/user_uploads",
|
2018-02-13 22:48:48 +01:00
|
|
|
fallback_id: file_input, // Target for standard file dialog
|
2017-11-23 15:00:05 +01:00
|
|
|
paramname: "file",
|
2019-05-03 17:55:04 +02:00
|
|
|
max_file_upload_size: page_params.max_file_upload_size,
|
2017-11-23 15:00:05 +01:00
|
|
|
data: {
|
|
|
|
// the token isn't automatically included in filedrop's post
|
|
|
|
csrfmiddlewaretoken: csrf_token,
|
|
|
|
},
|
|
|
|
raw_droppable: ['text/uri-list', 'text/plain'],
|
2018-04-14 10:11:18 +02:00
|
|
|
drop: drop,
|
2018-04-14 11:48:22 +02:00
|
|
|
uploadStarted: uploadStarted,
|
2018-02-13 22:39:51 +01:00
|
|
|
progressUpdated: progressUpdated,
|
|
|
|
error: uploadError,
|
|
|
|
uploadFinished: uploadFinished,
|
2017-11-23 15:00:05 +01:00
|
|
|
rawDrop: function (contents) {
|
|
|
|
if (!compose_state.composing()) {
|
|
|
|
compose_actions.start('stream');
|
|
|
|
}
|
2018-02-13 22:48:48 +01:00
|
|
|
textarea.val(textarea.val() + contents);
|
2017-11-23 15:00:05 +01:00
|
|
|
compose_ui.autosize_textarea();
|
|
|
|
},
|
2018-02-13 22:39:51 +01:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2019-10-25 09:45:13 +02:00
|
|
|
window.upload = exports;
|