MediaWiki:Gadget-RechercheDeCatégorie.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).
  • Internet Explorer / Edge : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl + F5.
  • Opera : appuyez sur Ctrl + F5.
function sanitize(word) {
	return word
		.replace(/&/g, "&")
		.replace(/</g, "&lt;")
		.replace(/>/g, "&gt;")
		.replace(/"/g, "&quot;")
		.replace(/'/g, "&#039;");
}

function normalizeString(str) {
	return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
}

$(document).ready(function() {
	// À afficher uniquement sur les pages du namespace "Catégorie"
	if (mw.config.get('wgNamespaceNumber') === 14) {

		// Sauvegarde le contenu original de la page
		var originalCategoryGenerated = $('#mw-category-media').html();
		var originalCategoryMedia = $('#mw-category-media').html();
		var originalPages = $('#mw-pages').html();
		var originalParserOutput = $('.mw-parser-output').html();
		var originalCatlinks = $('#catlinks').html();
		var originalPageTitle = $('.mw-page-title-main').text();
		var originalNamespace = $('.mw-page-title-namespace').text();
		var originalSeparator = $('.mw-page-title-separator').text();

		// Ajoute une barre de recherche en haut de la page
		var searchBar = '<div id="categorySearch" style="display: flex; margin-bottom: 5px">' +
						'<div id="categorySearchBar" class="vector-search-box-inner" data-search-loc="header-navigation">' +
						'<input class="vector-search-box-input" type="search" name="search" placeholder="Rechercher un média dans la catégorie" aria-label="Rechercher un média dans la catégorie" autocapitalize="sentences" title="Rechercher un média dans la catégorie [alt-shift-g]" accesskey="g" id="categorySearchInput">' +
						'<input id="mw-searchButton" class="searchButton mw-fallbackSearchButton" type="submit" name="fulltext" title="Rechercher les pages comportant ce texte." value="Rechercher" style="margin-right: 10px;">' +
						'<input id="searchButton" class="searchButton" type="submit" name="go" title="Rechercher les éléments de la catégorie qui correspondent à votre recherche" value="Lire">' +
						'</div>' +
						'<div style="display: flex; align-items: center; margin-left: 10px;" class="vector-body">' +
						'<input type="checkbox" id="caseSensitive" name="caseSensitive" style="margin-right: 5px;">' +
						'<label for="caseSensitive">Respecter la casse</label>' +
						'<div style="margin: 0px 5px">•</div>' +
						'<input type="checkbox" id="includeSubcategories" name="includeSubcategories" style="margin-right: 5px;">' +
						'<label for="includeSubcategories">Inclure les sous-catégories</label>' +
						'<div style="margin: 0px 5px">•</div>' +
						'<button id="closeCategorySearch" title="Annuler la recherche" style="background-color: #FAFBFC; border: 1px solid rgba(27, 31, 35, 0.3); border-radius: 6px; cursor: pointer; line-height: 20px">Annuler la recherche</button>' +
						'</div>' +
						'</div>';

		// Vérifie si la barre de recherche existe déjà
		if (!$('#categorySearch').length) {
			$('#content').prepend(searchBar);
		}

		// Fonction de recherche et d'affichage
		function performSearch() {
			var searchTerm = $('#categorySearchInput').val();
			var isCaseSensitive = $('#caseSensitive').is(':checked');
			var includeSubcategories = $('#includeSubcategories').is(':checked');
			var normalizedSearchTerm = isCaseSensitive ? searchTerm : normalizeString(searchTerm);
			var categoryName = mw.config.get('wgPageName').replace('Catégorie:', '').replace(/_/g, ' ');

			// Changer le titre de la page sans modifier le titre de l'onglet
			$('.mw-page-title-namespace').hide();
			$('.mw-page-title-separator').hide();
			$('.mw-page-title-main').text('Recherche dans « Catégorie:' + categoryName + ' »');

			// Masquer le contenu original
			$('#mw-subcategories').hide();
			$('#mw-category-media').hide();
			$('#mw-pages').hide();

			// Fonction pour récupérer les fichiers MediaWiki via l'API
			function fetchFiles(term, category) {
				return $.ajax({
					url: mw.util.wikiScript('api'),
					data: {
						action: 'query',
						list: 'categorymembers',
						cmtitle: 'Catégorie:' + category,
						cmtype: 'file',
						cmlimit: 'max',
						cmprop: 'title',
						format: 'json'
					},
					dataType: 'json'
				});
			}

			// Fonction pour récupérer les sous-catégories via l'API
			function fetchSubcategories(category) {
				return $.ajax({
					url: mw.util.wikiScript('api'),
					data: {
						action: 'query',
						list: 'categorymembers',
						cmtitle: 'Catégorie:' + category,
						cmtype: 'subcat',
						cmlimit: 'max',
						format: 'json'
					},
					dataType: 'json'
				});
			}

			// Fonction récursive pour récupérer les fichiers de toutes les sous-catégories
			function fetchAllFiles(category, visitedCategories) {
				if (visitedCategories[category]) {
					return $.Deferred().resolve([]).promise(); // Retourne une promesse résolue avec un tableau vide si déjà visité
				}
				visitedCategories[category] = true;

				var allFiles = [];

				return fetchFiles(normalizedSearchTerm, category).then(function(data) {
					allFiles = data.query.categorymembers;

					if (includeSubcategories) {
						return fetchSubcategories(category).then(function(subcatData) {
							var subcategories = subcatData.query.categorymembers;
							var subcatPromises = subcategories.map(function(subcategory) {
								var subcategoryName = subcategory.title.replace('Catégorie:', '');
								return fetchAllFiles(subcategoryName, visitedCategories);
							});

							return $.when.apply($, subcatPromises).then(function() {
								$.each(arguments, function(i, subFiles) {
									allFiles = allFiles.concat(subFiles);
								});
								return allFiles;
							});
						});
					} else {
						return allFiles;
					}
				});
			}

			// Fonction pour filtrer et afficher les fichiers
			function displayFiles(files) {
				var filteredFiles = files.filter(function(file) {
					var fileTitle = file.title.replace('Fichier:', '');
					return isCaseSensitive 
						? fileTitle.includes(searchTerm) 
						: normalizeString(fileTitle).includes(normalizedSearchTerm);
				});

				// Tri des fichiers par ordre alphabétique du titre
				filteredFiles.sort(function(a, b) {
					return a.title.localeCompare(b.title);
				});

				var resultsCount = filteredFiles.length;
				var resultsText = resultsCount < 2 ? 'résultat' : 'résultats';

				var galleryHtml = '<h2 class="search-results-title">Média trouvés avec la recherche « ' + sanitize(searchTerm) + ' »</h2>' +
								  '<p class="search-results-count">La recherche a donné ' + resultsCount + ' ' + resultsText + '.</p>' +
								  '<div id="mw-category-media-search">' +
								  '<div class="gallery mw-gallery-traditional" style="display: flex; flex-wrap: wrap; gap: 5px;">';
				filteredFiles.forEach(function(file) {
					var fileName = file.title.toLowerCase();
					var isMP4 = fileName.endsWith('.mp4');
					var isOGG = fileName.endsWith('.ogg');
					var fileUrl = mw.util.getUrl('Special:FilePath/' + file.title.replace('Fichier:', ''));

					var thumbHtml = '';

					if (isMP4) {
						// Générer une vignette pour les fichiers MP4
						thumbHtml = '<video width="150" height="150" controls>' +
									'<source src="' + fileUrl + '" type="video/mp4">' +
									'Your browser does not support the video tag.' +
									'</video>';
					} else if (isOGG) {
						// Générer une vignette pour les fichiers OGG
						thumbHtml = '<audio controls style="width: 150px;">' +
									'<source src="' + fileUrl + '" type="audio/ogg">' +
									'Your browser does not support the audio element.' +
									'</audio>';
					} else {
						thumbHtml = '<img src="' + fileUrl + '" alt="' + file.title + '" style="max-width: 100%; max-height: 100%; object-fit: contain; object-position: center;">';
					}

					galleryHtml += '<div class="gallerybox" style="margin: 5px; width: 160px;">' +
								   '<div class="thumb" style="width: 150px; height: 150px; overflow: hidden; border: 1px solid #ccc; background: #f7f7f7; display: flex; align-items: center; justify-content: center; padding: 5px;">' +
								   '<a href="' + mw.util.getUrl(file.title) + '" class="image" style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">' +
								   thumbHtml + '</a></div>' +
								   '<div class="gallerytext" style="text-align: center; margin-top: 5px;">' +
								   '<p class="galleryfilename" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin: 0;">' +
								   '<a href="' + mw.util.getUrl(file.title) + '">' + file.title.replace('Fichier:', '') + '</a></p>' +
								   '</div></div>';
				});
				galleryHtml += '</div></div>';
				$('#mw-category-media').before(galleryHtml); // Insère la galerie avant mw-category-media
			}

			// Efface les résultats précédents
			$('#mw-category-media-search').remove();
			$('.search-results-title').remove(); // Supprime les titres précédents
			$('.search-results-count').remove(); // Supprime les compteurs précédents

			// Recherche les fichiers et les affiche
			fetchAllFiles(categoryName, {}).done(function(files) {
				displayFiles(files);
			}).fail(function() {
				alert('Une erreur est survenue lors de la recherche des fichiers.');
			});
		}

		// Ajoute un événement pour le bouton de recherche
		$('#searchButton').off('click').on('click', performSearch);
		$('#mw-searchButton').off('click').on('click', performSearch);

		// Ajoute un événement pour la touche Entrée dans la barre de recherche
		$('#categorySearchInput').off('keypress').on('keypress', function(event) {
			if (event.which === 13) {
				performSearch();
			}
		});

		// Ajoute un événement pour le bouton de fermeture
		$('#closeCategorySearch').off('click').on('click', function() {
			$('.mw-parser-output').html(originalParserOutput).show(); // Restaure le contenu original et l'affiche
			$('#mw-category-media').html(originalCategoryMedia).show();
			$('#mw-pages').html(originalPages).show();
			$('#mw-subcategories').show(); // Restaure le contenu original et l'affiche
			$('#catlinks').html(originalCatlinks).show(); // Restaure le contenu original et l'affiche
			$('.mw-page-title-main').text(originalPageTitle); // Restaure le titre principal original
			$('.mw-page-title-namespace').text(originalNamespace).show();
			$('.mw-page-title-separator').text(originalSeparator).show();
			$('#mw-category-media-search').remove(); // Supprime les résultats de recherche
			$('.search-results-title').remove(); // Supprime les titres de résultats de recherche
			$('.search-results-count').remove(); // Supprime les compteurs de résultats de recherche
		});
	}
});