MediaWiki:MultiUpload.js

/* @authors Gguigui1, KhangND, Universal Omega */ $.when(mw.loader.using([ "mediawiki.user", "mediawiki.api", "jquery.client", "jquery.spinner" ])).then(function {			return new mw.Api				.get({ action: "query", meta: "siteinfo", siprop: "fileextensions", format: "json", })				.then(function (data) { var extensions = data.query.fileextensions, e; var FileExtensions = []; for (e in extensions) { FileExtensions.push(extensions[e].ext); }					mw.config.set({						'wgFileExtensions': FileExtensions					}); var groups = mw.config.get('wgUserGroups').join, config = mw.config.get([							'wgCanonicalSpecialPageName',							'wgNamespaceNumber',							'wgTitle',							'wgUserLanguage',							'wgUserName'						]); mw.loader.implement("mediawiki.legacy.ajax", function ($) {						window.sajax_debug_mode = !1;						window.sajax_request_type = 'GET';						window.sajax_debug = function (text) {							if (!sajax_debug_mode)								return false;							var e = document.getElementById('sajax_debug');							if (!e) {								e = document.createElement('p');								e.className = 'sajax_debug';								e.id = 'sajax_debug';								var b = document.getElementsByTagName('body')[0];								if (b.firstChild) {									b.insertBefore(e, b.firstChild);								} else {									b.appendChild(e);								}							}							var m = document.createElement('div');							m.appendChild(document.createTextNode(text));							e.appendChild(m);							return true;						};						window.sajax_init_object = function {							sajax_debug('sajax_init_object called..');							var A;							try {								A = new XMLHttpRequest;							} catch (e) { try { A = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { A = new ActiveXObject('Microsoft.XMLHTTP'); } catch (oc) { A = null; }								}							}							if (!A) { sajax_debug('Could not create connection object.'); }							return A;						}; window.sajax_do_call = function (func_name, args, target) { var i, x, n;							var uri; var post_data; uri = mw.util.wikiScript + '?action=ajax'; if (sajax_request_type == 'GET') { if (uri.indexOf('?') == -1) { uri = uri + '?rs=' + encodeURIComponent(func_name); } else { uri = uri + '&rs=' + encodeURIComponent(func_name); }								for (i = 0; i < args.length; i++) { uri = uri + '&rsargs[]=' + encodeURIComponent(args[i]); }								post_data = null; } else { post_data = 'rs=' + encodeURIComponent(func_name); for (i = 0; i < args.length; i++) { post_data = post_data + '&rsargs[]=' + encodeURIComponent(args[i]); }							}							x = sajax_init_object; if (!x) { alert('AJAX not supported'); return false; }							try { x.open(sajax_request_type, uri, true); } catch (e) { if (window.location.hostname == 'localhost') { alert("Your browser blocks XMLHttpRequest to 'localhost', try using a real hostname for development/testing."); }								throw e;							} if (sajax_request_type == 'POST') { x.setRequestHeader('Method', 'POST ' + uri + ' HTTP/1.1'); x.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); }							x.setRequestHeader('Pragma', 'cache=yes'); x.setRequestHeader('Cache-Control', 'no-transform'); x.onreadystatechange = function { if (x.readyState != 4) { return; }								sajax_debug('received (' + x.status + ' ' + x.statusText + ') ' + x.responseText); if (typeof (target) == 'function') { target(x); } else if (typeof (target) == 'object') { if (target.tagName == 'INPUT') { if (x.status == 200) { target.value = x.responseText; }									} else { if (x.status == 200) { target.innerHTML = x.responseText; } else { target.innerHTML = ' Error: ' + x.status + ' ' + x.statusText + ' (' + x.responseText + ') '; }									}								} else { alert('bad target for sajax_do_call: not a function or object: ' + target); }							};							sajax_debug(func_name + ' uri = ' + uri + ' / post = ' + post_data); x.send(post_data); sajax_debug(func_name + ' waiting..'); delete x;							return true; };						window.wfSupportsAjax = function { var request = sajax_init_object; var supportsAjax = request ? true : !1; delete request; return supportsAjax; };;					}, {}, {});

function getLicensePreview(num) { window.licenseSelectorCheck = function { var selector = document.getElementById("license" + num); var selection = selector.options[selector.selectedIndex].value; if (selector.selectedIndex > 0) { if (selection == "") { // Option disabled, but browser is broken and doesn't respect this selector.selectedIndex = 0; }							}							var UploadLicenseObj = {

'responseCache': { : 								},

'fetchPreview': function (license) { for (cached in this.responseCache) { if (cached == license) { this.showPreview(this.responseCache[license]); return; }									}									$('#license' + num).injectSpinner('license' + num);

var title = document.getElementById('imagename' + num).value; if (!title) title = 'File:Sample.jpg';

var url = mw.util.wikiScript('api') + '?action=parse&text=' + '&title=' + encodeURIComponent(title) + '&prop=text&pst&format=json';

var req = sajax_init_object; req.onreadystatechange = function { if (req.readyState == 4 && req.status == 200) { UploadLicenseObj.processResult(eval('(' + req.responseText + ')'), license); }									};									req.open('GET', url, true); req.send('');

},

'processResult': function (result, license) { $.removeSpinner('license' + num); this.responseCache[license] = result['parse']['text']['*']; this.showPreview(this.responseCache[license]); },

'showPreview': function (preview) { var previewPanel = document.getElementById('mw-license-preview' + num); if (previewPanel.innerHTML != preview) previewPanel.innerHTML = preview; }

};							// We might show a preview UploadLicenseObj.fetchPreview(selection); };						var wpLicense = document.getElementById('license' + num);

if (wpLicense) { // License selector check wpLicense.onchange = licenseSelectorCheck;

// License selector table row var wpLicenseRow = wpLicense.parentNode.parentNode; var wpLicenseTbody = wpLicenseRow.parentNode;

var row = document.createElement('tr'); var td = document.createElement('td'); row.appendChild(td); td = document.createElement('td'); td.id = 'mw-license-preview' + num; row.appendChild(td);

wpLicenseTbody.insertBefore(row, wpLicenseRow.nextSibling); }					}					// load protections if (window.MultiUploadLoaded ||						config.wgUserName === null ||						!/autoconfirmed/.test(groups)) { return; }					window.MultiUploadLoaded = true; var storage = 'MultiUploadLicenses'; var content = $('#mw-content-text'); var allowTypes = $.map(mw.config.get("wgFileExtensions"), function (file_extensions) {						return ('.' + file_extensions)					});

var style = { block: { display: 'inline-block', margin: '0 8px' },						textarea: { width: '100%', height: 150, boxSizing: 'border-box', resize: 'none' }					};

function loadMWMessagesIfMissing(messages) { var deferred = $.Deferred, missingMessages = messages.filter(function (message) {								return !mw.messages.exists(message);							}); if (!missingMessages.length) { deferred.resolve; } else { $.get(mw.util.wikiScript('api'), {								format: 'json',								action: 'query',								meta: 'allmessages',								ammessages: missingMessages.join('|'),								amlang: config.wgUserLanguage							}).then(function (data) {								if ($.isArray(data.query.allmessages)) {									$.each(data.query.allmessages, function (_, message) { if (message.missing !== '') { mw.messages.set(message.name, message['*']); }									});								}								deferred.resolve;							}, function {								// Silently swallow failures; we don't want error reporting to stall just because we failed to fetch some messages.								deferred.resolve;							}); }						return deferred; }

MultiUpload = { input: $, // available on init editor: $, // available on init button: $, // available on init fileCount: 0, // available on create preload: function (load) { $.extend(this, window.MultiUploadoption || {}); this.load = load;

// creates Special page if (								(config.wgNamespaceNumber === -1 && config.wgTitle === 'MultiUpload') ||								(config.wgCanonicalSpecialPageName === 'Blankpage' && /MultiUpload/.test($.getUrlVar('blankspecial')))							) { $('#firstHeading').text('Multi Upload'); $('title').text('Multi Upload'); this.init; }						},						init: function { content.empty.append([								$(' ', { id: 'fileinput', type: 'file', multiple: true, accept: allowTypes.join, }),								$(' ', {									id: 'editor', css: { display: 'none' },								}),								$(' ', {									id: 'go', text: 'Update the form', click: $.proxy(this.getLicenses, this) })							]);							this.input = $('#fileinput'); this.editor = $('#editor'); this.button = $('#go'); },						notify: function (message, type) { new BannerNotification(message, type, null).show; },						getLicenses: function { var data = localStorage.getItem(storage); if (data !== null) { this.create(data); if (this.enableLicensePreview !== false) { var limit = this.max < this.fileCount ? this.max : this.fileCount; for (i = 1; i <= limit; i++) { getLicensePreview(i); }								}								return;

}

$.get(mw.util.wikiScript('api'), {								action: 'query',								meta: 'allmessages',								ammessages: 'Licenses',								format: 'json'							}).success(								$.proxy(this.create, this)							).error($.proxy(function (data) { this.notify('Api Error : ' + data.error.info, 'error'); }), this); },						create: function (data) { // conditions var formatError = false; this.fileCount = this.input[0].files.length;

$(this.input[0].files).each(function (i, file) {								if (!new RegExp(allowTypes.join('|\\'), 'i').test(file.name)) {									formatError = true;									return;								}							}); if (formatError) { this.notify('Unsupported file format', 'warn'); return; }							if (!this.input[0].files) { this.notify('This browser doesn&#39;t seem to support the `files` property of file inputs.', 'notify'); return; }							if (this.fileCount === 0) { this.notify('You have to choose a file to upload it', 'warn'); return; }							if (!this.max ||								this.max < 0 ||								this.max > 101 ||								typeof this.max !== 'number') { if (/staff|helper|util|bot-global/.test(groups)) { this.max = 200; } else if (/bureaucrat|bot/.test(groups)) { this.max = 70; } else if (/sysop/.test(groups)) { this.max = 50; } else if (/rollback/.test(groups)) { this.max = 30; } else { this.max = 20; }							}							if (!this.max) { this.notify('A problem occurred, upload cancelled', 'error'); return; }

// creates form data = typeof data === 'object' ? data.query.allmessages[0]['*'].trim : data; localStorage.setItem(storage, data); // retrieves licenses 1 time only var licenses = data.split('\n'); var limit = this.max < this.fileCount ? this.max : this.fileCount; for (i = 1; i <= limit; i++) { $(' ', {									id: 'field' + i,									appendTo: this.editor,									append: [										$(' ', { text: 'File n° ' + i										}),										$(' ', { css: style.block, text: 'Name:', append: $(' ', {												type: 'text',												id: 'imagename' + i,												'class': 'imagename',												val: this.input[0].files[i - 1].name											}) }),										$(' ', {											css: style.block, text: 'License:', append: $(' ', {												id: 'license' + i,												'class': 'license',												append: $(' ', { val: 'none', text: 'None selected' })											})										}),

$(' ', {											id: 'progress' + i,											css: style.block										}), ]

});

}							for (i = 0; i < licenses.length; i++) { if (licenses[i].indexOf('**') === 0) { var name = licenses[i].split('|')[0].replace('**', '').trim, text = licenses[i].split('|')[1]; $(' ', {										val: name,										text: text,										selected: name == this.defaultlicense,										appendTo: $('.license').find('optgroup:last-child')									}); } else { $(' ', {										label: licenses[i].replace('*', '').trim,										appendTo: $('.license')									}); }							}							$(' ', {									appendTo: this.editor,									text: 'Summaries:'								}), $(' ', {									appendTo: this.editor,									id: 'UploadDescription',									css: style.textarea,								}) $('.license option[value="none"').attr("disabled", "true"); $(' ', {									'class': 'secondary',									id: 'reset',									css: style.block,									text: 'Reset the form',									click: $.proxy(this.init, this),									appendTo: content								}), $(' ', {									type: 'checkbox',									id: 'ignorewarnings',									name: 'ignorewarnings',									appendTo: content								}), $(' ', {									'for': 'ignorewarnings',									text: 'Ignore warnings',									appendTo: content								}); jQuery(function ($) {								'use strict';

if (this.defaultDescription) { if ($('#UploadDescription').val) { return; }									var params = { action: 'parse', page: this.defaultDescription, format: 'json', prop: 'wikitext' };									var api = new mw.Api;

api.get(params).done(function (data) {										$('#UploadDescription').val(data.parse.wikitext['*']);									}); }								$('.license option[value="none"]').attr("disabled", "true"); });

license = $('#license' + i).find('option:selected').val,

this.input.attr('disabled', true); this.editor.show; this.button .unbind('click') .click($.proxy(this.upload, this)) .text('Upload All'); },						upload: function { content.find('*').attr('disabled', true); $('#reset').removeAttr('disabled');

var obj = this;

var loop = function (i) { if (i <= obj.fileCount) { var file = obj.input[0].files[i - 1], filename = $('#imagename' + i).val || file.name, license = $('#license' + i).find('option:selected').val, text = $('#UploadDescription').val; if (license == "none" && this.requireLicensing === true) { alert('Licensing must be complete.'); $('*').removeAttr('disabled'); return; }

if (license !== "none") text = '== Summary ==\n' + text + '\n\n== Licensing ==\n\n'; obj.uploadFile(file, filename, text, i).always(function {										loop(i + 1);									}); }							};							loop(1); },						uploadFile: function (fileToUpload, fileName, text, index) { // https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects formdata = new FormData; formdata.append('action', 'upload'); formdata.append('format', 'json'); formdata.append('filename', fileName); formdata.append('token', mw.user.tokens.get('editToken')); formdata.append('file', fileToUpload); formdata.append('text', text); formdata.append(								$('#ignorewarnings').prop('checked') ? 'ignorewarnings' : , 							);

// https://stackoverflow.com/a/8244082 return $.ajax({								url: mw.util.wikiScript('api'),								contentType: false,								processData: false,								type: 'POST',								data: formdata,								dataType: 'json',								xhr: function { // https://stackoverflow.com/a/27030092									myXhr = $.ajaxSettings.xhr;									myXhr.upload.addEventListener('progress', function (e) { MultiUpload.progress(index, e); });									return myXhr;								},								success: $.proxy(function (data) { this.success(index, data); }, this),								error: $.proxy(function (_, __, error) { this.notify(error, 'error'); }, this)							}); },						progress: function (index, e) { var progress = e.loaded / e.total * 100; $('#progress' + index).text(progress.toFixed(0) + '%'); },						success: function (index, data) { // Error if (data.error) { var errorInfo, errorDetails;

function displayError { $('#progress' + index).html([										$(' ').text(errorInfo),										(errorDetails === undefined) ? null : $(' '),										(errorDetails === undefined) ? null : $(' ').text(errorDetails)									]); }

// Excluding variants of `unknownerror`, we're going to ignore `error.info` since it mightn't be localized. if (data.error.code.startsWith('unknownerror')) { errorInfo = data.error.info; displayError; } else { var messages = [data.error.code]; if (data.error.code === 'verification-error') { messages.push(data.error.details[0]); }									loadMWMessagesIfMissing(messages).then(function {										errorInfo = mw.msg(data.error.code);										if (data.error.code === 'verification-error') {											errorDetails = mw.msg.apply(null, data.error.details);										} else if (data.error.code === 'hookaborted') {											errorDetails = data.error.error; // TODO: Determine whether it's safe to assume this'll always be properly escaped HTML.										}										displayError;									}); }								return; }

// Success if (data.upload.result === 'Success') { $('#progress' + index).text('File uploaded successfully.'); return; }

// Warnings var msg; if (data.upload.warnings.hasOwnProperty('was-deleted')) { msg = 'Deleted file'; } else if (data.upload.warnings.hasOwnProperty('duplicate')) { msg = 'Duplicated file'; } else if (data.upload.warnings.hasOwnProperty('exists')) { msg = 'Existing file'; } else { msg = 'File uploaded successfully.'; }

$('#progress' + index).text(msg); }					};

$(function (load) {						$.proxy(MultiUpload.preload, MultiUpload);					}); });