refactor: Extract upload mechanics to new JS module.

Tweaked by tabbott to move changes from the next commit that are
required for this to pass tests into this commit.

Note that this exports a few items that were not previously exported.
This commit is contained in:
Tommy Ip 2017-11-23 14:00:05 +00:00 committed by Tim Abbott
parent 0445322625
commit ddaff4cd2a
6 changed files with 147 additions and 130 deletions

View File

@ -150,6 +150,7 @@
"recent_senders": false,
"unread_ui": false,
"unread_ops": false,
"upload": false,
"user_events": false,
"Plotly": false,
"emoji_codes": false,

View File

@ -52,6 +52,7 @@ zrequire('stream_data');
zrequire('compose_state');
zrequire('people');
zrequire('compose');
zrequire('upload');
page_params.use_websockets = false;
var me = {
@ -1296,7 +1297,7 @@ function test_with_mock_socket(test_params) {
return 'fake-html';
};
compose.uploadStarted();
upload.uploadStarted();
assert.equal($("#compose-send-button").attr("disabled"), '');
assert($("#send-status").hasClass("alert-info"));
@ -1311,7 +1312,7 @@ function test_with_mock_socket(test_params) {
assert.equal(width_percent, '39%');
width_update_checked = true;
};
compose.progressUpdated(1, '', 39);
upload.progressUpdated(1, '', 39);
assert(width_update_checked);
}());
@ -1336,7 +1337,7 @@ function test_with_mock_socket(test_params) {
function test(err, file, msg) {
setup_test();
compose.uploadError(err, file);
upload.uploadError(err, file);
// The text function and html function in zjquery is not in sync
// with each other. QuotaExceeded changes html while all other errors
// changes body.
@ -1420,7 +1421,7 @@ function test_with_mock_socket(test_params) {
}
setup();
compose.uploadFinished(i, {}, response);
upload.uploadFinished(i, {}, response);
assert_side_effects();
}

View File

@ -19,113 +19,11 @@ exports.uploads_path = '/user_uploads';
exports.uploads_re = new RegExp("\\]\\(" + exports.uploads_domain + "(" + exports.uploads_path + "[^\\)]+)\\)", 'g');
exports.clone_file_input = undefined;
function make_upload_absolute(uri) {
if (uri.indexOf(exports.uploads_path) === 0) {
// Rewrite the URI to a usable link
return exports.uploads_domain + uri;
}
return uri;
}
function make_uploads_relative(content) {
// Rewrite uploads in markdown links back to domain-relative form
return content.replace(exports.uploads_re, "]($1)");
}
// This function resets an input type="file". Pass in the
// jquery object.
function clear_out_file_list(jq_file_list) {
if (exports.clone_file_input !== undefined) {
jq_file_list.replaceWith(exports.clone_file_input.clone(true));
}
// Hack explanation:
// IE won't let you do this (untested, but so says StackOverflow):
// $("#file_input").val("");
}
exports.uploadStarted = function () {
$("#compose-send-button").attr("disabled", "");
$("#send-status").addClass("alert-info")
.show();
$(".send-status-close").one('click', exports.abort_xhr);
$("#error-msg").html(
$("<p>").text(i18n.t("Uploading…"))
.after('<div class="progress progress-striped active">' +
'<div class="bar" id="upload-bar" style="width: 00%;"></div>' +
'</div>'));
};
exports.progressUpdated = function (i, file, progress) {
$("#upload-bar").width(progress + "%");
};
exports.uploadError = function (err, file) {
var msg;
$("#send-status").addClass("alert-error")
.removeClass("alert-info");
$("#compose-send-button").prop("disabled", false);
switch (err) {
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':
// sanitization not needed as the file name is not potentially parsed as HTML, etc.
var context = { file_name: file.name };
msg = i18n.t('"__file_name__" was too large; the maximum file size is 25MiB.', context);
break;
case 'REQUEST ENTITY TOO LARGE':
msg = i18n.t("Sorry, the file was too large.");
break;
case 'QuotaExceeded':
var translation_part1 = i18n.t('Upload would exceed your maximum quota. You can delete old attachments to free up space.');
var translation_part2 = i18n.t('Click here');
msg = translation_part1 + ' <a href="#settings/uploaded-files">' + translation_part2 + '</a>';
$("#error-msg").html(msg);
return;
default:
msg = i18n.t("An unknown error occurred.");
break;
}
$("#error-msg").text(msg);
};
exports.uploadFinished = function (i, file, response) {
if (response.uri === undefined) {
return;
}
var textbox = $("#new_message_content");
var split_uri = response.uri.split("/");
var filename = split_uri[split_uri.length - 1];
// Urgh, yet another hack to make sure we're "composing"
// when text gets added into the composebox.
if (!compose_state.composing()) {
compose_actions.start('stream');
}
var uri = make_upload_absolute(response.uri);
if (i === -1) {
// This is a paste, so there's no filename. Show the image directly
textbox.val(textbox.val() + "[pasted image](" + uri + ") ");
} else {
// This is a dropped file, so make the filename a link to the image
textbox.val(textbox.val() + "[" + filename + "](" + uri + ")" + " ");
}
compose_ui.autosize_textarea();
$("#compose-send-button").prop("disabled", false);
$("#send-status").removeClass("alert-info")
.hide();
// In order to upload the same file twice in a row, we need to clear out
// the #file_input element, so that the next time we use the file dialog,
// an actual change event is fired. This is extracted to a function
// to abstract away some IE hacks.
clear_out_file_list($("#file_input"));
};
function show_all_everyone_warnings() {
var stream_count = stream_data.get_subscriber_count(compose_state.stream_name()) || 0;
@ -872,29 +770,7 @@ exports.initialize = function () {
Dropbox.choose(options);
});
$("#compose").filedrop({
url: "/json/user_uploads",
fallback_id: "file_input",
paramname: "file",
maxfilesize: page_params.maxfilesize,
data: {
// the token isn't automatically included in filedrop's post
csrfmiddlewaretoken: csrf_token,
},
raw_droppable: ['text/uri-list', 'text/plain'],
drop: exports.uploadStarted,
progressUpdated: exports.progressUpdated,
error: exports.uploadError,
uploadFinished: exports.uploadFinished,
rawDrop: function (contents) {
var textbox = $("#new_message_content");
if (!compose_state.composing()) {
compose_actions.start('stream');
}
textbox.val(textbox.val() + contents);
compose_ui.autosize_textarea();
},
});
upload.initialize();
if (page_params.narrow !== undefined) {
if (page_params.narrow_topic !== undefined) {

138
static/js/upload.js Normal file
View File

@ -0,0 +1,138 @@
var upload = (function () {
var exports = {};
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;
}
// This function resets an input type="file". Pass in the
// jquery object.
function clear_out_file_list(jq_file_list) {
if (compose.clone_file_input !== undefined) {
jq_file_list.replaceWith(compose.clone_file_input.clone(true));
}
// Hack explanation:
// IE won't let you do this (untested, but so says StackOverflow):
// $("#file_input").val("");
}
exports.uploadStarted = function () {
$("#compose-send-button").attr("disabled", "");
$("#send-status").addClass("alert-info").show();
$(".send-status-close").one('click', compose.abort_xhr);
$("#error-msg").html($("<p>").text(i18n.t("Uploading…"))
.after('<div class="progress progress-striped active">' +
'<div class="bar" id="upload-bar" style="width: 00%;"></div>' +
'</div>'));
};
exports.progressUpdated = function (i, file, progress) {
$("#upload-bar").width(progress + "%");
};
exports.uploadError = function (err, file) {
var msg;
$("#send-status").addClass("alert-error")
.removeClass("alert-info");
$("#compose-send-button").prop("disabled", false);
switch (err) {
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':
// sanitization not needed as the file name is not potentially parsed as HTML, etc.
var context = {
file_name: file.name,
};
msg = i18n.t('"__file_name__" was too large; the maximum file size is 25MiB.', context);
break;
case 'REQUEST ENTITY TOO LARGE':
msg = i18n.t("Sorry, the file was too large.");
break;
case 'QuotaExceeded':
var translation_part1 = i18n.t('Upload would exceed your maximum quota. You can delete old attachments to free up space.');
var translation_part2 = i18n.t('Click here');
msg = translation_part1 + ' <a href="#settings/uploaded-files">' + translation_part2 + '</a>';
$("#error-msg").html(msg);
return;
default:
msg = i18n.t("An unknown error occurred.");
break;
}
$("#error-msg").text(msg);
};
exports.uploadFinished = function (i, file, response) {
if (response.uri === undefined) {
return;
}
var textbox = $("#new_message_content");
var split_uri = response.uri.split("/");
var filename = split_uri[split_uri.length - 1];
// Urgh, yet another hack to make sure we're "composing"
// when text gets added into the composebox.
if (!compose_state.composing()) {
compose_actions.start('stream');
}
var uri = make_upload_absolute(response.uri);
if (i === -1) {
// This is a paste, so there's no filename. Show the image directly
textbox.val(textbox.val() + "[pasted image](" + uri + ") ");
} else {
// This is a dropped file, so make the filename a link to the image
textbox.val(textbox.val() + "[" + filename + "](" + uri + ")" + " ");
}
compose_ui.autosize_textarea();
$("#compose-send-button").prop("disabled", false);
$("#send-status").removeClass("alert-info")
.hide();
// In order to upload the same file twice in a row, we need to clear out
// the #file_input element, so that the next time we use the file dialog,
// an actual change event is fired. This is extracted to a function
// to abstract away some IE hacks.
clear_out_file_list($("#file_input"));
};
exports.initialize = function () {
$("#compose").filedrop({
url: "/json/user_uploads",
fallback_id: "file_input",
paramname: "file",
maxfilesize: page_params.maxfilesize,
data: {
// the token isn't automatically included in filedrop's post
csrfmiddlewaretoken: csrf_token,
},
raw_droppable: ['text/uri-list', 'text/plain'],
drop: exports.uploadStarted,
progressUpdated: exports.progressUpdated,
error: exports.uploadError,
uploadFinished: exports.uploadFinished,
rawDrop: function (contents) {
var textbox = $("#new_message_content");
if (!compose_state.composing()) {
compose_actions.start('stream');
}
textbox.val(textbox.val() + contents);
compose_ui.autosize_textarea();
},
});
};
return exports;
}());
if (typeof module !== 'undefined') {
module.exports = upload;
}

View File

@ -236,7 +236,7 @@ def build_custom_checkers(by_lang):
'frontend_tests/node_tests/compose.js',
'frontend_tests/node_tests/copy_and_paste.js',
'frontend_tests/node_tests/templates.js',
'static/js/compose.js',
'static/js/upload.js',
'static/js/dynamic_text.js',
'static/js/stream_color.js',
]),

View File

@ -977,6 +977,7 @@ JS_SPECS = {
'js/compose_state.js',
'js/compose_actions.js',
'js/compose.js',
'js/upload.js',
'js/stream_color.js',
'js/stream_data.js',
'js/topic_data.js',