/* * addonUploader() * 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; } function checkTimeout(validation) { var timeout_id = [ 'validator', 'unexpected_exception', 'validation_timeout', ]; return _.some(validation.messages, function (message) { return _.isEqual(message.id, timeout_id); }); } $.fn.addonUploader = function (options) { var settings = { filetypes: ['zip', 'xpi', 'crx'], getErrors: getErrors, cancel: $(), maxSize: null, // Dynamically set by devhub.js submissionsDisabled: false, }; if (options) { $.extend(settings, options); } function parseErrorsFromJson(response, statusCode) { 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 = $('
', { class: 'invisible-upload prominent cta', id: 'upload-file-widget', }), ui_link = $('', { class: 'button prominent', href: '#', text: gettext('Select a file...'), }), ui_details = $('
', { class: 'upload-details', text: gettext('Your add-on should end with .zip, .xpi or .crx'), }); ui_link.toggleClass('disabled', settings.submissionsDisabled); $upload_field.prop('disabled', settings.submissionsDisabled); $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 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}'), [ formatFileSize(size), formatFileSize(file.size), ]), ); } } /* Bind the events */ $upload_field.on('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(); /* Set defaults */ $('#id_is_manual_review').prop('checked', false); /* Don't allow submitting */ // The create theme wizard button is actually a link, // so it's pointless to set the disabled property on it, // instead add the special "concealed" class. $('.addon-create-theme-section .button').addClass('concealed'); $('.addon-upload-dependant').prop('disabled', true); $('.addon-upload-failure-dependant').prop({ disabled: true, checked: false, }); /* Create elements */ upload_title = $('', { id: 'upload-status-text' }); upload_progress_outside = $('
', { id: 'upload-status-bar' }); upload_progress_inside = $('
').css('width', 0); upload_status = $('
', { id: 'uploadstatus' }).hide(); upload_status_percent = $(''); upload_status_progress = $(''); upload_status_cancel_a = $('', { href: '#', text: gettext('Cancel'), }); upload_status_cancel = $(' · '); upload_results = $('
', { id: 'upload-status-results' }); upload_box = $('
', { 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(' · '); 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.on('upload_progress', function (e, file, pct) { upload_progress_inside.animate( { width: pct + '%' }, { duration: 300, step: function (i) { updateStatus(i, file.size); }, }, ); }); $upload_field.on('upload_errors', function (e, file, errors, results) { var all_errors = $.extend([], errors); // be nice to other handlers upload_progress_inside.stop().css({ width: '100%' }); if ($('input#id_upload').val()) { $('.addon-upload-failure-dependant').prop({ disabled: false, checked: false, }); } $('.addon-create-theme-section .button').removeClass('concealed'); $upload_field.val('').prop('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(); $('') .text( gettext( 'Please make sure to report any linting related issues on GitHub', ), ) .attr('href', 'https://github.com/mozilla/addons-linter/') .attr('class', 'addons-linter-info') .attr('target', '_blank') .attr('rel', 'noopener noreferrer') .appendTo(upload_results); var error_message = format( ngettext( 'Your add-on failed validation with {0} error.', 'Your add-on failed validation with {0} errors.', all_errors.length, ), [all_errors.length], ); $('').text(error_message).appendTo(upload_results); var errors_ul = $('