Aller au contenu

MediaWiki:Gadget-multiupload.js

De Poképédia

Note : après avoir publié vos modifications, il se peut que vous deviez forcer le rechargement complet du cache de votre navigateur pour voir les changements.

  • Firefox / Safari : maintenez la touche Maj (Shift) en cliquant sur le bouton Actualiser ou appuyez sur Ctrl + F5 ou Ctrl + R (⌘ + R sur un Mac).
  • Google Chrome : appuyez sur Ctrl + Maj + R (⌘ + Shift + R sur un Mac).
  •  Edge : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl + F5.
function sanitize(word) {
	return word
		.replace(/&/g, "&")
		.replace(/</g, "&lt;")
		.replace(/>/g, "&gt;")
		.replace(/"/g, "&quot;")
		.replace(/'/g, "&#039;");
}

function createFilePreview(file, isPerFile) {
	var filePreview = "";
	if (file.name.endsWith('.mp4')) {
		filePreview = '<video width="220" height="150" controls>' +
			'<source src="' + URL.createObjectURL(file) + '" type="video/mp4">' +
			'</video>';
	} else if (file.name.endsWith('.ogg')) {
		filePreview = '<div style="width:220px"><audio controls style="width: 220px;">' +
		'<source src="' + URL.createObjectURL(file) + '" type="audio/ogg">' +
		'</audio></div>';
	} else {
		if (isPerFile) {
			filePreview = $('<img>').attr('src', URL.createObjectURL(file)).css({
				'max-width': '100%',
				'max-height': '150px',
				'display': 'block',
				'margin-left': '10px'
			});
		} else {
			filePreview = $('<img>').attr('src', URL.createObjectURL(file)).css({
				'max-width': '220px',
				'max-height': '150px'
			});
			
		}
	}
	return filePreview;
}

$(function() {
	// Ajouter un lien "Téléversement multiple" à la barre latérale
	var sidebarLink = $('<li id="t-multiupload" class="mw-list-item">').append(
		$('<a>').attr('href', '#').text('Téléversement multiple')
	);

	$('#t-upload').after(sidebarLink);
	
	// Variables globales
	var wasPreviousFileUploaded = true;
	var defaultDescription = "";
	var moduleDescriptionDescription = '{{#' +
		'invoke:Description|sprite|source=}}';
	var teraRaidDescription = "Image pour le [[cristal de raid " +
		"événementiel XXX]].\n\n" +
		"{{Informations Fichier\n" +
		"| source=[https://serebii.net/scarletviolet/teraraidbattleevents.shtml " +
		"Serebii]\n" +
		"| auteur=[[GAME FREAK (studio de développement)" +
		"|GAME FREAK]]\n" +
		"}}\n\n" +
		"[[Catégorie:Image de raid "+
		"Téracristal événementiel]]\n" +
		"[[Catégorie:Image Pokémon " +
		"représentant XXX]]";

	// Lorsque le lien est cliqué, afficher le modal de sélection de mode
	sidebarLink.on('click', function(event) {
		event.preventDefault();
		showOptionModal();
	});

	function showOptionModal() {
		var modal = $('<div>').addClass('mw-body-content').css({
			'position': 'fixed',
			'top': '50%',
			'left': '50%',
			'transform': 'translate(-50%, -50%)',
			'background-color': '#FFF',
			'padding': '15px',
			'box-shadow': '0px 0px 20px rgba(0, 0, 0, 0.3)',
			'z-index': '1001',
			'width': '700px',
			'line-height': '22.4px',
			'border-radius': '10px',
			'border': 'solid 1px #888'
		});

		var title = $('<h2>').text('Téléversement multiple').css({
			'margin-bottom': '10px',
		});

		var description = "<div style='font-size:14px'><p>Utilisez ce formulaire pour téléverser plusieurs fichiers à la fois sur le serveur. " +
			"Pour voir ou rechercher des images précédemment envoyées, consultez la <a href='/Spécial:Liste_des_fichiers' title='Spécial:Liste des fichiers'>liste des fichiers téléversés</a>.</p>" +
			"<p>Avant de téléverser un nouveau fichier, assurez-vous d'avoir lu la <a href='/Aide:Ajouter_une_image' title='Aide:Ajouter une image'>page d'aide dédiée</a>. " +
			"Elle contient des éléments essentiels concernant le format, la classification et le bon usage des fichiers.</p>" +
			"<p>Mal utilisé, les modifications engendrées par ce gadget peuvent s'avérer très longues à réparer. " +
			"Ne l'utilisez pas n'importe comment.</p>" +
			'<hr style="margin:10px 0px;">' +
			"<p>Sélectionnez une option pour renseigner la description des fichiers à importer :</p></div>";
		
		var buttonContainer = $('<div>').css({
			'display': 'flex',
			'justify-content': 'space-between',
			'margin-top': '15px'
		});

		var perFileBtn = $('<button>').text('Description par fichier').css({
			'padding': '10px',
			'background-color': '#3366CC',
			'color': '#FFF',
			'border': 'none',
			'border-radius': '5px',
			'cursor': 'pointer',
			'width': '32%',
			'font-size': '14px',
			'font-weight': 'bold'
		});

		var globalDescriptionBtn = $('<button>').text('Description globale').css({
			'padding': '10px',
			'background-color': '#3366CC',
			'color': '#FFF',
			'border': 'none',
			'border-radius': '5px',
			'cursor': 'pointer',
			'width': '32%',
			'font-size': '14px',
			'font-weight': 'bold'
		});

		var cancelBtn = $('<button>').text('Annuler').css({
			'padding': '10px',
			'background-color': '#CCC',
			'color': '#000',
			'border': 'none',
			'border-radius': '5px',
			'cursor': 'pointer',
			'width': '32%',
			'font-size': '14px',
			'font-weight': 'bold'
		});

		perFileBtn.on('click', function() {
			modal.remove();
			openFileSelector(true);
		});

		globalDescriptionBtn.on('click', function() {
			modal.remove();
			openFileSelector(false);
		});

		cancelBtn.on('click', function() {
			modal.remove();
		});

		buttonContainer.append(perFileBtn, globalDescriptionBtn, cancelBtn);
		modal.append(title, description, buttonContainer);
		$('body').append(modal);
	}

	function openFileSelector(isPerFile) {
		var fileInput = $('<input>').attr({
			'type': 'file',
			'multiple': 'multiple'
		}).css('display', 'none');

		fileInput.on('change', function(event) {
			var files = event.target.files;
			if (files.length > 0) {
				if (isPerFile) {
					handleFiles(files);
				} else {
					createGlobalDescriptionModal(files);
				}
			}
		});

		fileInput.click();
	}

	function handleFiles(files) {
		var fileArray = Array.from(files);
		var index = 0;

		function nextFile() {
			if (index < fileArray.length) {
				createUploadModal(fileArray[index], index + 1, fileArray.length, function() {
					index++;
					nextFile();
				});
			} else {
				if (wasPreviousFileUploaded) {
					alert("Le dernier fichier a bien été téléversé.");
				} else {
					alert("Le dernier fichier n'a pas été téléversé.");
				}
			}
		}

		nextFile();
	}

	function createUploadModal(file, fileIndex, totalFiles, callback) {
		var modal = $('<div>').addClass('mw-body-content').css({
			'position': 'fixed',
			'top': '50%',
			'left': '50%',
			'transform': 'translate(-50%, -50%)',
			'background-color': '#FFF',
			'padding': '15px',
			'box-shadow': '0px 0px 20px rgba(0, 0, 0, 0.3)',
			'z-index': '1001',
			'border-radius': '10px',
			'border': 'solid 1px #888'
		});

		var title = $('<h2>').text('Téléverser des fichiers (' + fileIndex + '/' + totalFiles + ')');
		
		var previousFileState = $('<p>').css({
			'font-size': '14px',
			'margin': '0px'
		});
		if (wasPreviousFileUploaded) {
			previousFileState.css('color', 'green');
			previousFileState.text('Le fichier précédent a bien été téléversé.');
		} else {
			previousFileState.css('color', 'red');
			previousFileState.text("Le fichier précédent n'a pas été téléversé.");
		}

		var fileNameLabel = $('<label>').text('Nom du fichier').css({
			'display': 'block',
			'margin-bottom': '5px',
			'font-weight': 'bold'
		});

		var fileNameInput = $('<input>').attr('type', 'text').val(file.name).css({
			'width': '100%',
			'padding': '10px',
			'box-sizing': 'border-box',
			'border': '1px solid #CCC',
			'border-radius': '5px'
		});
		
		var fileNameContainer = $('<div>');
		fileNameContainer.append(fileNameLabel, fileNameInput);
		
		var upperContent = $('<div>').css({
			'width': '100%',
			'display': 'flex',
			'flex-direction': 'column',
			'justify-content': 'space-between'
		});
		
		// Pour un espacement plus harmonieux
		var spacingContainer = $('<div>').css({
			'height': '5px'
		});
		
		if (fileIndex === 1) {
			upperContent.append(title, fileNameContainer, spacingContainer);
		} else {
			upperContent.append(title, previousFileState, fileNameContainer, spacingContainer);
		}
		
		
		var filePreview = createFilePreview(file, true);
		
		var upperContainer = $('<div>').css({
			'display': 'flex'
		});
		
		upperContainer.append(upperContent, filePreview);

		var descriptionLabel = $('<label>').text('Description du fichier').css({
			'display': 'block',
			'margin-bottom': '5px',
			'font-weight': 'bold'
		});
		
		var defaultDescriptionTemplate = "<!-- Remplacer cette ligne par la description du fichier -->\n\n" +
			"{{Informations Fichier\n" +
			"| source=<!-- Indiquer un lien vers l'endroit où le fichier a été obtenu, ou le nom de l'utilisateur l'ayant créé -->\n" +
			"| auteur=<!-- Indiquer l'auteur de l'image au sens juridique (développeur du jeu, etc) -->\n" +
			"}}\n\n" +
			"<!-- Remplacer cette ligne par la catégorisation du fichier -->";
		
		if (fileIndex === 1) {
			defaultDescription = defaultDescriptionTemplate;
		}

		var descriptionInput = $('<textarea>').attr('placeholder', 'Entrer la description du fichier').text(defaultDescription).css({
			'width': '700px',
			'height': '170px',
			'padding': '10px',
			'margin-bottom': '10px',
			'box-sizing': 'border-box',
			'border': '1px solid #CCC',
			'border-radius': '5px'
		});

		var buttonContainer = $('<div>').css({
			'display': 'flex',
			'white-space': 'nowrap'
		});
		
		var descriptionOptions = [
			{text: 'Description par défaut', value: defaultDescriptionTemplate},
			{text: 'Module description', value: moduleDescriptionDescription},
			{text: 'Image de raid Téracristal', value: teraRaidDescription}
		];
	
		var descriptionSelect = $('<select>').css({
			'width': '100%',
			'min-width': '200px',
			'padding': '10px',
			'box-sizing': 'border-box',
			'border': '1px solid #CCC',
			'border-radius': '5px'
		});
	
		descriptionOptions.forEach(function(option) {
			descriptionSelect.append($('<option>').text(option.text).val(option.value));
		});
	
		descriptionSelect.on('change', function() {
			descriptionInput.val($(this).val());
			defaultDescription = $(this).val();
		});

		var uploadBtn = $('<button>').text('Téléverser').css({
			'padding': '10px 20px',
			'background-color': '#3366CC',
			'color': '#FFF',
			'border': 'none',
			'border-radius': '5px',
			'cursor': 'pointer',
			'font-size': '14px',
			'font-weight': 'bold',
			'margin-left': '10px'
		});

		var cancelBtn = $('<button>').text('Annuler').css({
			'padding': '10px 20px',
			'background-color': '#CCC',
			'color': '#000',
			'border': 'none',
			'border-radius': '5px',
			'cursor': 'pointer',
			'font-size': '14px',
			'font-weight': 'bold',
			'margin-left': '10px'
		});

		var cancelAllBtn = $('<button>').text('Annuler tout').css({
			'padding': '10px 20px',
			'background-color': '#CCC',
			'color': '#000',
			'border': 'none',
			'border-radius': '5px',
			'cursor': 'pointer',
			'font-size': '14px',
			'font-weight': 'bold',
			'margin-left': '10px'
		});

		uploadBtn.on('click', function() {
			uploadBtn.css({
				'cursor': 'wait',
				'background-color': '#7A95CC'
			});
			uploadBtn.text("Téléversement en cours...");
			uploadFile(file, fileNameInput.val(), descriptionInput.val(), modal, callback);
		});

		cancelBtn.on('click', function() {
			wasPreviousFileUploaded = false;
			modal.remove();
			// Pour éviter d'afficher l'état du dernier fichier s'il a été annulé
			if (fileIndex != totalFiles) {
				callback();
			}
		});

		cancelAllBtn.on('click', function() {
			wasPreviousFileUploaded = false;
			modal.remove();
			// Reset the file handling process
		});

		buttonContainer.append(descriptionSelect, uploadBtn, cancelBtn, cancelAllBtn);
		modal.append(upperContainer, descriptionLabel, descriptionInput, buttonContainer);
		$('body').append(modal);
	}

	function uploadFile(file, fileName, description, modal, callback) {
		var formData = new FormData();
		var text = description;
		if (!text.includes("== Description ==")) {
			text = "== Description ==\n" + text;
		}
		formData.append('file', file);
		formData.append('filename', fileName);
		formData.append('text', text);
		formData.append('comment', description);
		formData.append('action', 'upload');
		formData.append('tags', 'multiupload');
		formData.append('ignorewarnings', '1');
		formData.append('format', 'json');
		formData.append('token', mw.user.tokens.get('csrfToken'));

		$.ajax({
			url: mw.util.wikiScript('api'),
			type: 'POST',
			data: formData,
			processData: false,
			contentType: false,
			success: function(response) {
				if (response.upload && response.upload.result === 'Success') {
					wasPreviousFileUploaded = true;
				} else {
					wasPreviousFileUploaded = false;
					console.error(response);
				}
				modal.remove();
				callback();
			},
			error: function(xhr, status, error) {
				wasPreviousFileUploaded = false;
				console.error(error);
				modal.remove();
				callback();
			}
		});
	}

	function createGlobalDescriptionModal(files) {
		var fileNames = [];
		for (i = 0; i < files.length; i++) {
			fileNames[i] = files[i].name;
		}
		
		var modal = $('<div>').addClass('mw-body-content').css({
			'position': 'fixed',
			'top': '50%',
			'left': '50%',
			'transform': 'translate(-50%, -50%)',
			'background-color': '#FFF',
			'padding': '15px',
			'box-shadow': '0px 0px 20px rgba(0, 0, 0, 0.3)',
			'z-index': '1001',
			'border-radius': '10px',
			'border': 'solid 1px #888'
		});

		var s = '';
		if (files.length > 1) {
			s = 's';
		}

		var title = $('<h2>').text('Téléverser ' + files.length + ' fichier' + s).css({
			'margin-bottom': '25px'
		});

		var description = $('<p>').text('Les fichiers auront tous la description suivante.').css({
			'font-size': '14px',
			'margin-bottom': '20px'
		});
		
		var upperContent = $('<div>').css({
			'width': '100%'
		});
		
		upperContent.append(title, description);

		var descriptionLabel = $('<label>').text('Description des fichiers').css({
			'display': 'block',
			'margin-bottom': '5px',
			'font-weight': 'bold'
		});
		
		var defaultDescription = "<!-- Remplacer cette ligne par la description des fichiers -->\n\n" +
			"{{Informations Fichier\n" +
			"| source=<!-- Indiquer un lien vers l'endroit où les fichiers ont été obtenus, ou le nom de l'utilisateur les ayant créés -->\n" +
			"| auteur=<!-- Indiquer l'auteur des images au sens juridique (développeur du jeu, etc) -->\n" +
			"}}\n\n" +
			"<!-- Remplacer cette ligne par la catégorisation des fichiers -->";

		var descriptionInput = $('<textarea>').attr('placeholder', 'Entrer la description des fichiers').text(defaultDescription).css({
			'width': '700px',
			'height': '170px',
			'padding': '10px',
			'margin-bottom': '10px',
			'box-sizing': 'border-box',
			'border': '1px solid #CCC',
			'border-radius': '5px'
		});

		var filePreviewContainer = $('<div>').css({
			'width': '220px',
			'height': '150px'
		});
		var filePanel = $('<div>');
		
		var fileContainer = $('<div>').css({
			'display': 'flex',
			'align-items': 'center',
			'text-align': 'center',
			'margin-left': '5px'
		});

		var leftArrow = $('<button>').text('<').css({
			'padding': '5px 10px',
			'margin-right': '10px',
			'background-color': '#CCC',
			'color': '#000',
			'border': 'none',
			'border-radius': '5px',
			'cursor': 'pointer',
			'font-size': '14px',
			'font-weight': 'bold'
		});

		var rightArrow = $('<button>').text('>').css({
			'padding': '5px 10px',
			'margin-left': '10px',
			'background-color': '#CCC',
			'color': '#000',
			'border': 'none',
			'border-radius': '5px',
			'cursor': 'pointer',
			'font-size': '14px',
			'font-weight': 'bold',
		});

		var filePreviewIndex = 0;
		var filePreview = $('<div>').html(createFilePreview(files[filePreviewIndex], false));
		filePreviewContainer.append(filePreview);
		
		var fileTextInput = $('<input>').val(sanitize(fileNames[filePreviewIndex])).css({
			'margin-bottom': '0px',
			'margin-top': '5px',
			'padding': '10px',
			'box-sizing': 'border-box',
			'border': '1px solid #CCC',
			'border-radius': '5px',
			'width': '100%'
		});
		
		fileTextInput.on('input', function() {
			fileNames[filePreviewIndex] = $(this).val();
		});
		
		function showPreviousImage() {
			if (filePreviewIndex > 0) {
				filePreviewIndex--;
			} else {
				filePreviewIndex = files.length - 1;
			}
			filePreview.html(createFilePreview(files[filePreviewIndex], false));
			fileTextInput.val(fileNames[filePreviewIndex]);
		}
		
		function showNextImage() {
			if (filePreviewIndex < files.length - 1) {
				filePreviewIndex++;
			} else {
				filePreviewIndex = 0;
			}
			filePreview.html(createFilePreview(files[filePreviewIndex], false));
			fileTextInput.val(fileNames[filePreviewIndex]);
		}

		leftArrow.on('click', showPreviousImage);
		rightArrow.on('click', showNextImage);
		
		window.addEventListener('keydown', function(event) {
			if (event.target.matches('input, textarea, select, button')) {
				return;
			}
			
			if (event.key === 'ArrowLeft') {
				showPreviousImage();
			} else if (event.key === 'ArrowRight') {
				showNextImage();
			}
		});
		
		if (files.length > 1) {
			fileContainer.append(leftArrow, filePreviewContainer, rightArrow);
		} else {
			fileContainer.append(filePreviewContainer);
		}
		
		filePanel.append(fileContainer, fileTextInput);
		
		var upperContainer = $('<div>').css({
			'display': 'flex'
		});
		
		upperContainer.append(upperContent, filePanel);

		var buttonContainer = $('<div>').css({
			'display': 'flex',
			'white-space': 'nowrap'
		});
		
		var descriptionOptions = [
			{text: 'Description par défaut', value: defaultDescription},
			{text: 'Module description', value: moduleDescriptionDescription},
			{text: 'Image de raid Téracristal', value: teraRaidDescription}
		];
	
		var descriptionSelect = $('<select>').css({
			'width': '100%',
			'min-width': '200px',
			'padding': '10px',
			'box-sizing': 'border-box',
			'border': '1px solid #CCC',
			'border-radius': '5px'
		});
	
		descriptionOptions.forEach(function(option) {
			descriptionSelect.append($('<option>').text(option.text).val(option.value));
		});
	
		descriptionSelect.on('change', function() {
			descriptionInput.val($(this).val());
		});

		var uploadBtn = $('<button>').text('Téléverser tout').css({
			'padding': '10px 20px',
			'background-color': '#3366CC',
			'color': '#FFF',
			'border': 'none',
			'border-radius': '5px',
			'cursor': 'pointer',
			'font-size': '14px',
			'font-weight': 'bold',
			'margin-left': '10px'
		});

		var cancelBtn = $('<button>').text('Annuler').css({
			'padding': '10px 20px',
			'background-color': '#CCC',
			'color': '#000',
			'border': 'none',
			'border-radius': '5px',
			'cursor': 'pointer',
			'font-size': '14px',
			'font-weight': 'bold',
			'margin-left': '10px'
		});

		uploadBtn.on('click', function() {
			uploadBtn.css({
				'cursor': 'wait',
				'background-color': '#7A95CC'
			});
			uploadBtn.text("Téléversement en cours...");
			uploadAllFilesSequentially(files, fileNames, descriptionInput.val(), modal);
		});

		cancelBtn.on('click', function() {
			modal.remove();
		});

		buttonContainer.append(descriptionSelect, uploadBtn, cancelBtn);
		modal.append(upperContainer, descriptionLabel, descriptionInput, buttonContainer);
		$('body').append(modal);

		function uploadAllFilesSequentially(files, fileNames, description, modal) {
			var index = 0;
			var failedFiles = [];
	
			function uploadNextFile() {
				uploadBtn.text("Téléversement en cours... (" + (index + 1) + "/" + files.length + ")");
				if (index < files.length) {
					var file = files[index];
					var fileName = fileNames[index];
					var formData = new FormData();
					var text = description;
					if (!text.includes("== Description ==")) {
						text = "== Description ==\n" + text;
					}
					formData.append('file', file);
					formData.append('filename', fileName);
					formData.append('text', text);
					formData.append('comment', description);
					formData.append('action', 'upload');
					formData.append('tags', 'multiupload');
					formData.append('ignorewarnings', '1');
					formData.append('format', 'json');
					formData.append('token', mw.user.tokens.get('csrfToken'));
	
					$.ajax({
						url: mw.util.wikiScript('api'),
						type: 'POST',
						data: formData,
						processData: false,
						contentType: false,
						success: function(response) {
							if (response.upload && response.upload.result === 'Success') {
								console.log('Fichier téléversé avec succès : ' + fileName);
							} else {
								console.error('Erreur lors du téléversement du fichier : ' + fileName, response);
								failedFiles.push(fileName);
							}
							index++;
							uploadNextFile();
						},
						error: function(xhr, status, error) {
							console.error('Erreur lors du téléversement du fichier : ' + fileName, error);
							index++;
							uploadNextFile();
						}
					});
				} else {
					if (failedFiles.length > 0) {
						alert("Le téléversement des fichiers est terminé. Les fichiers suivants n'ont pas pu être téléversés :\n" + failedFiles.join('\n'));
					} else {
						alert('Tous les fichiers ont bien été téléversés.');
					}
					modal.remove();
				}
			}
	
			uploadNextFile();
		}
	}
});