331 строка
14 KiB
JavaScript
331 строка
14 KiB
JavaScript
/*
|
|
* packagedAppUploader()
|
|
* Extends fileUploader()
|
|
* Also, this can only be used once per page. Or you'll have lots of issues with closures and scope :)
|
|
*/
|
|
|
|
(function($) {
|
|
/* Normalize results */
|
|
function getErrors(results) {
|
|
var errors = [];
|
|
|
|
if (results.validation.messages) {
|
|
$.each(results.validation.messages, function(i, v) {
|
|
if (v.type == 'error') {
|
|
errors.push(v.message);
|
|
}
|
|
});
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
$.fn.packagedAppUploader = function( options ) {
|
|
var settings = {'filetypes': ['zip'], 'getErrors': getErrors, 'cancel': $()};
|
|
|
|
if (options) {
|
|
$.extend( settings, options );
|
|
}
|
|
|
|
function parseErrorsFromJson(response) {
|
|
var json, errors = [];
|
|
try {
|
|
json = JSON.parse(response);
|
|
} catch (err) {
|
|
errors = [gettext('There was a problem contacting the server.')];
|
|
}
|
|
if (!errors.length) {
|
|
errors = settings['getErrors'](json);
|
|
}
|
|
return {
|
|
errors: errors,
|
|
json: json
|
|
}
|
|
}
|
|
|
|
return $(this).each(function() {
|
|
var $upload_field = $(this),
|
|
file = {};
|
|
|
|
/* Add some UI */
|
|
|
|
var ui_parent = $('<div>', {'class': 'invisible-upload prominent cta', 'id': 'upload-file-widget'}),
|
|
ui_link = $('<a>', {'class': 'button prominent', 'href': '#', 'text': gettext('Select a file...')}),
|
|
ui_details = $('<div>', {'class': 'upload-details', 'html': gettext('Your packaged app should end with <code>.zip</code>.')});
|
|
|
|
$upload_field.attr('disabled', false);
|
|
$upload_field.wrap(ui_parent);
|
|
$upload_field.before(ui_link);
|
|
$upload_field.parent().after(ui_details);
|
|
|
|
if (!z.capabilities.fileAPI) {
|
|
$('.invisible-upload').addClass('legacy');
|
|
}
|
|
|
|
/* Get things started */
|
|
|
|
var upload_box, upload_title, upload_progress_outside, upload_progress_inside,
|
|
upload_status, upload_results, upload_status_percent, upload_status_progress,
|
|
upload_status_cancel;
|
|
|
|
$upload_field.fileUploader(settings);
|
|
|
|
function textSize(bytes) {
|
|
// Based on code by Cary Dunn (http://bit.ly/d8qbWc).
|
|
var s = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
|
if (bytes === 0) {
|
|
return bytes + ' ' + s[1];
|
|
}
|
|
var e = Math.floor( Math.log(bytes) / Math.log(1024) );
|
|
return (bytes / Math.pow(1024, Math.floor(e))).toFixed(2)+' '+s[e];
|
|
}
|
|
|
|
function updateStatus(percentage, size) {
|
|
if (percentage) {
|
|
upload_status.show();
|
|
p = Math.round(percentage);
|
|
size = (p / 100) * size;
|
|
|
|
// L10n: {0} is the percent of the file that has been uploaded.
|
|
upload_status_percent.text(format(gettext('{0}% complete'), [p]));
|
|
|
|
// L10n: "{bytes uploaded} of {total filesize}".
|
|
upload_status_progress.text(format(gettext('{0} of {1}'),
|
|
[textSize(size), textSize(file.size)]));
|
|
}
|
|
}
|
|
|
|
/* Bind the events */
|
|
|
|
$upload_field.bind('upload_start', function(e, _file) {
|
|
file = _file;
|
|
|
|
/* Remove old upload box */
|
|
if (upload_box) {
|
|
upload_box.remove();
|
|
}
|
|
|
|
/* Remove old errors */
|
|
$upload_field.closest('form').find('.errorlist').remove();
|
|
|
|
/* Don't allow submitting */
|
|
$('.addon-upload-dependant').attr('disabled', true);
|
|
|
|
/* Create elements */
|
|
upload_title = $('<strong>', {'id': 'upload-status-text'});
|
|
upload_progress_outside = $('<div>', {'id': 'upload-status-bar'});
|
|
upload_progress_inside = $('<div>').css('width', 0);
|
|
upload_status = $('<div>', {'id': 'uploadstatus'}).hide();
|
|
upload_status_percent = $('<span>');
|
|
upload_status_progress = $('<span>');
|
|
upload_status_cancel_a = $('<a>', {'href': '#', 'text': gettext('Cancel')});
|
|
upload_status_cancel = $('<span> · </span>');
|
|
upload_results = $('<div>', {'id': 'upload-status-results'});
|
|
upload_box = $('<div>', {'class': 'upload-status ajax-loading'}).hide();
|
|
|
|
/* Set up structure */
|
|
upload_box.append(upload_title);
|
|
upload_progress_outside.append(upload_progress_inside);
|
|
upload_box.append(upload_progress_outside);
|
|
upload_status.append(upload_status_percent);
|
|
upload_status.append(' <span> · </span> ');
|
|
upload_status.append(upload_status_progress);
|
|
upload_status.append(upload_status_cancel);
|
|
upload_status_cancel.append(upload_status_cancel_a);
|
|
|
|
upload_box.append(upload_status);
|
|
upload_box.append(upload_results);
|
|
|
|
/* Add to the dom and clean up upload_field */
|
|
ui_details.after(upload_box);
|
|
|
|
/* It's showtime! */
|
|
upload_title.html(format(gettext('Uploading {0}'), [escape_(file.name)]));
|
|
upload_box.show();
|
|
|
|
upload_box.addClass('ajax-loading');
|
|
|
|
upload_status_cancel_a.click(_pd(function() {
|
|
$upload_field.trigger('upload_action_abort');
|
|
}));
|
|
});
|
|
|
|
$upload_field.bind('upload_progress', function(e, file, pct) {
|
|
upload_progress_inside.animate({'width': pct + '%'},
|
|
{duration: 300, step:function(i) { updateStatus(i, file.size); } });
|
|
});
|
|
|
|
$upload_field.bind('upload_errors', function(e, file, errors, results) {
|
|
var all_errors = $.extend([], errors); // be nice to other handlers
|
|
upload_progress_inside.stop().css({'width': '100%'});
|
|
|
|
$upload_field.val('').attr('disabled', false);
|
|
$upload_field.trigger('reenable_uploader');
|
|
|
|
upload_title.html(format(gettext('Error with {0}'), [escape_(file.name)]));
|
|
|
|
upload_progress_outside.attr('class', 'bar-fail');
|
|
upload_progress_inside.fadeOut();
|
|
|
|
var error_message = format(ngettext(
|
|
'Your app failed validation with {0} error.',
|
|
'Your app failed validation with {0} errors.',
|
|
all_errors.length), [all_errors.length]);
|
|
|
|
$('<strong>').text(error_message).appendTo(upload_results);
|
|
|
|
var errors_ul = $('<ul>', {'id': 'upload_errors'});
|
|
|
|
$.each(all_errors.splice(0, 5), function(i, error) {
|
|
errors_ul.append($('<li>', {'html': error }));
|
|
});
|
|
|
|
if (all_errors.length > 0) {
|
|
var message = format(ngettext('…and {0} more',
|
|
'…and {0} more',
|
|
all_errors.length), [all_errors.length]);
|
|
errors_ul.append($('<li>', {'html': message}));
|
|
}
|
|
|
|
upload_results.append(errors_ul).addClass('status-fail');
|
|
|
|
if (results && results.full_report_url) {
|
|
// There might not be a link to the full report
|
|
// if we get an early error like unsupported type.
|
|
upload_results.append($('<a>', {'href': results.full_report_url,
|
|
'class': 'view-more',
|
|
'target': '_blank',
|
|
'text': gettext('See full validation report')}));
|
|
}
|
|
|
|
|
|
});
|
|
|
|
$upload_field.bind('upload_finished', function(e, file, results) {
|
|
upload_box.removeClass('ajax-loading');
|
|
upload_status_cancel.remove();
|
|
});
|
|
|
|
$upload_field.bind('upload_success', function(e, file, results) {
|
|
upload_title.html(format(gettext('Validating {0}'), [escape_(file.name)]));
|
|
|
|
var animateArgs = {duration: 300, step:function(i) { updateStatus(i, file.size); }, complete: function() {
|
|
$upload_field.trigger('upload_success_results', [file, results]);
|
|
}};
|
|
|
|
$('#id_upload').val(results.upload);
|
|
$('#id_packaged').attr('checked', true);
|
|
upload_progress_inside.animate({'width': '100%'}, animateArgs);
|
|
});
|
|
|
|
$upload_field.bind('upload_onreadystatechange', function(e, file, xhr, aborted) {
|
|
var errors = [],
|
|
$form = $upload_field.closest('form'),
|
|
json = {},
|
|
errOb;
|
|
if (xhr.readyState == 4 && xhr.responseText &&
|
|
(xhr.status == 200 ||
|
|
xhr.status == 304 ||
|
|
xhr.status == 400)) {
|
|
|
|
errOb = parseErrorsFromJson(xhr.responseText);
|
|
errors = errOb.errors;
|
|
json = errOb.json;
|
|
|
|
if (errors.length > 0) {
|
|
$upload_field.trigger('upload_errors', [file, errors, json]);
|
|
} else {
|
|
$form.find('input#id_upload').val(json.upload);
|
|
$upload_field.trigger('upload_success', [file, json]);
|
|
$upload_field.trigger('upload_progress', [file, 100]);
|
|
}
|
|
$upload_field.trigger('upload_finished', [file]);
|
|
|
|
} else if (xhr.readyState == 4 && !aborted) {
|
|
// L10n: first argument is an HTTP status code
|
|
errors = [format(gettext('Received an empty response from the server; status: {0}'),
|
|
[xhr.status])];
|
|
|
|
$upload_field.trigger('upload_errors', [file, errors]);
|
|
}
|
|
});
|
|
|
|
$upload_field.bind('upload_success_results', function(e, file, results) {
|
|
if (results.error) {
|
|
// This shouldn't happen. But it might.
|
|
var error = gettext('Unexpected server error while validating.');
|
|
$upload_field.trigger('upload_errors', [file, [error]]);
|
|
return;
|
|
}
|
|
|
|
// Validation results? If not, fetch the json again.
|
|
if (! results.validation) {
|
|
upload_progress_outside.attr('class', 'progress-idle');
|
|
// Not loaded yet. Try again!
|
|
setTimeout(function() {
|
|
$.ajax({
|
|
url: results.url,
|
|
dataType: 'json',
|
|
success: function(r) {
|
|
$upload_field.trigger('upload_success_results', [file, r]);
|
|
},
|
|
error: function(xhr, textStatus, errorThrown) {
|
|
var errOb = parseErrorsFromJson(xhr.responseText);
|
|
$upload_field.trigger('upload_errors', [file, errOb.errors, errOb.json]);
|
|
$upload_field.trigger('upload_finished', [file]);
|
|
}
|
|
});
|
|
}, 1000);
|
|
} else {
|
|
var errors = getErrors(results),
|
|
v = results.validation;
|
|
if (errors.length > 0) {
|
|
$upload_field.trigger('upload_errors', [file, errors, results]);
|
|
return;
|
|
}
|
|
|
|
$upload_field.val('').attr('disabled', false);
|
|
|
|
/* Allow submitting */
|
|
$('.addon-upload-dependant').attr('disabled', false);
|
|
|
|
upload_title.html(format(gettext('Finished validating {0}'), [escape_(file.name)]));
|
|
|
|
var message = '';
|
|
|
|
var warnings = v.warnings + v.notices;
|
|
if (warnings > 0) {
|
|
message = format(ngettext(
|
|
'Your app passed validation with no errors and {0} warning.',
|
|
'Your app passed validation with no errors and {0} warnings.',
|
|
warnings), [warnings]);
|
|
} else {
|
|
message = gettext('Your app passed validation with no errors or warnings.');
|
|
}
|
|
|
|
upload_progress_outside.attr('class', 'bar-success');
|
|
upload_progress_inside.fadeOut();
|
|
|
|
$('footer.listing-footer').removeClass('hidden');
|
|
$('button.upload-file-submit').removeAttr('disabled').focus();
|
|
|
|
$upload_field.trigger('reenable_uploader');
|
|
upload_results.addClass('status-pass');
|
|
|
|
$('<strong>').text(message).appendTo(upload_results);
|
|
|
|
if (results.full_report_url) {
|
|
// There might not be a link to the full report
|
|
// if we get an early error like unsupported type.
|
|
upload_results.append($('<a>', {'href': results.full_report_url,
|
|
'target': '_blank',
|
|
'text': gettext('See full validation report')}));
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
};
|
|
})(jQuery);
|