Utilisateur:Seudo/sd recopier.js

La bibliothèque libre.

Note : après avoir enregistré 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 pressez Ctrl-F5 ou Ctrl-R (⌘-R sur un Mac) ;
  • Google Chrome : Appuyez sur Ctrl-Maj-R (⌘-Shift-R sur un Mac) ;
  • Internet Explorer : Maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl-F5 ;
  • Opera : Allez dans Menu → Settings (Opera → Préférences sur un Mac) et ensuite à Confidentialité & sécurité → Effacer les données d'exploration → Images et fichiers en cache.
/*
 Ce script permet de corriger des problèmes de décalage entre la couche texte 
(celle qui apparaît dans le champ d'édition en mode Page lorsque la page n'a
pas encore été créée) et le fac similé. Il prend le contenu du champ d'édition
dans chaque page et l’enregistre dans la page située au même indice + un décalage. Il n’agit
pas si la page d’origine ou la page de destination existe déjà.

Encore expérimental, mais utilisé tout de même sur plus de 100 pages entre
[[Page:Vasari - Vies des peintres - t1 t2, 1841.djvu/797]] et 
[[Page:Vasari - Vies des peintres - t1 t2, 1841.djvu/904]].

Demande confirmation à chaque page, par sécurité.
*/
$( function($) {
	nom_script = "Utilisateur:Seudo/sd recopier.js";
	
	mw.util.addPortletLink('p-cactions',
		'#',
		'Sd recopier',
		'sd-recopier',
		'Test');
		
	// À affiner probablement
	function newpage2url(page) {
		return "https://fr.wikisource.org/w/index.php?title=" + page + "&action=edit&redlink=1";
	}

	function ajaxPageWikiContent(page) {
		/* Exemple : api.php?action=query&prop=revisions&rvprop=content&format=jsonfm&formatversion=2&titles=Main%20Page */
		return $.ajax({
			url: mw.util.wikiScript('api'),
			type: 'GET',
			dataType: 'json',
			data: {
				action: 'query',
				format: 'json',
				formatversion: 2,
				titles:page
			}
		});
	}
	
	// Le format de data est celui retourné par la requête renvoyée par getPageWikiContent
	function pageWikiMissing(data) {
		console.log(data);
		res = ('query' in data 
			&& 'pages' in data.query 
			&& data.query.pages.length > 0 
			&& 'missing' in data.query.pages[0] 
			&& data.query.pages[0].missing);
		console.log("Résultat : " + res);
		return res;
	}
	
	function alertmsg(msg, args = null, callback = null) {
		errmsg = msg;
		if(args) {
			pluriel = (args.nbdone >= 2 ? "s" : "");
			errmsg += " (" + args.nbdone + " page" + pluriel + " déjà traitée" + pluriel + ").";
		}
		
		displayMsg(errmsg, callback);
	}
	
	function displayMsg(msg, callback = null) {
		OO.ui.alert(msg).done(function() {
			if(callback) 
				callback();
		});
	}
	
	function updatePages(page, wikitxt, callback, args) {
		/* Ex. api.php?action=edit&title=Test&summary=test%20summary&text=article%20content&basetimestamp=2007-08-24T12:34:54Z&token=123ABC */
		summary = 'Transfert de la couche texte depuis ' + args.page_base + "/" + args.premier + ' avec ' + nom_script;
		$.ajax({
			url: mw.util.wikiScript('api'),
			type: 'POST',
			// dataType: 'json',
			data: {
				action: 'edit',
				title: page,
				summary: summary,
				text: wikitxt,
				createonly: '', /* Principe : on n'écrase pas une page existante */
				token: mw.user.tokens.get('editToken')
			}
		})
		.done(function(data) {
			// Le transfert a réussi
			args.nbdone += 1;
			next_premier = (args.nbdecal > 0 ? args.premier - 1 : args.premier + 1);

			if((args.nbdecal > 0 && next_premier < args.dernier) 
					|| (args.nbdecal <= 0 && next_premier > args.dernier)) {
				// On a fini de tout renommer
				pluriel = (args.nbdone >= 2 ? "s" : "");
				alertmsg("Succès : " + args.nbdone + " page" + pluriel + " transférée" + pluriel + ".");
			}
			else {
				args.premier = next_premier;
				callback(args); // Appel récursif pour le suivant
			}
		})
		.fail(function(data, textStatus, errorThrown) {
			console.log("Échec de la requête Ajax : " + textStatus + ", " + errorThrown);
			console.log(data);
			pluriel = (args.nbdone >= 2 ? "s" : "");
			errmsg = "La requête Ajax a échoué : " + JSON.stringify(data)
				+ " (" + args.nbdone + " page" + pluriel + " transféré" + pluriel + ").";
			alertmsg(errmsg, args);
		});
	}
	
	// Fonction de renommage (récursive, s'arrête à la première erreur)
	function copiePages(args) {
		// On renomme la page correspondant à args.premier, puis on passe à la suivante par récursion
		frompage = args.page_base + "/" + args.premier;
		topage = args.page_base + "/" + (args.premier + args.nbdecal);

		OO.ui.confirm("Déplacement de " + frompage + " vers " + topage + " ?")
		.done(function(confirmed) {
			if(confirmed) {
				// On vérifie que frompage et topage n'existent pas
				ajaxPageWikiContent(frompage)
				.done(function(data) {
					if(pageWikiMissing(data)) {
						ajaxPageWikiContent(topage)
						.done(function(data) {
							if(pageWikiMissing(data)) {
								// Je n'ai rien trouvé dans l'API de Wikimedia pour récupérer la couche texte,
								// donc allons-y un peu plus brutalement...
								url = newpage2url(frompage);
								$.get(url, function(data) {
									tempdom = $('<div></div>').append($.parseHTML(data));
									textbox = tempdom.find("#wpTextbox1");
									if(textbox) {
										wikitxt = textbox.text();
										updatePages(topage, wikitxt, copiePages, args);
										/*
										alertmsg("Texte wiki dans " + frompage + " : " + wikitxt, args,
											function() {
												updatePages(topage, wikitxt, copiePages, args);
											});
										*/
									}
									else
										alertmsg("Pas trouvé de wpTextbox1 dans " + frompage, args);
										
									// Todo : mise à jour de toPage et récursivité...
								});
							}
							else {
								alertmsg("Impossible de continuer : " + topage + " existe déjà", args);
							}					
						})
						.fail(function(data) {
							alertmsg("La requête Ajax sur " + frompage + " a échoué : " + JSON.stringify(data), args);
						});
					}
					else {
						alertmsg("Impossible de continuer : " + frompage + " existe déjà", args);
					}
				})
				.fail(function(data) {
					alertmsg("La requête Ajax sur " + frompage + " a échoué : " + JSON.stringify(data), args);
				});
			} 
			else {
				pluriel = (args.nbdone >= 2 ? "s" : "");
				alert("Arrêt : " + args.nbdone + " page" + pluriel + " renommée" + pluriel + ".");
			}
		});

	}
	
	// Vérification des choix entrés par l'utilisateur et envoi
	function doit(form_dialog, document, from, to, nbdecal) {
		try {
			if(document.length == 0)
				throw "Vous n'avez pas entré le nom d'un document";
			document = document.trim();
			prefixe_livre = "Livre:";
			prefixe_user1 = "Utilisateur:";
			prefixe_user2 = "User:";
			if(document.startsWith(prefixe_livre))
				page_base = "Page:" + document.substring(prefixe_livre.length);
			else if(document.startsWith(prefixe_user1) || document.startsWith(prefixe_user2))
				page_base = document;
			else
				throw "Vous devez préciser un nom de livre (Livre:....djvu) ou une page de l'espace personnel (Utilisateur:...)";
			from = parseInt(from);
			to = parseInt(to);
			nbdecal = parseInt(nbdecal);
			if(from === NaN || to === NaN || nbdecal === NaN) 
				throw "Veuillez entrer des entiers dans tous les champs numériques";
			if(from <= 0 || to <= 0)
				throw "Veuillez entrer des entiers strictement positifs comme numéros de page";
			if(to < from)
				throw "La dernière page doit avoir un numéro supérieur ou égal à la première";
			pluriel = (nbdecal >= 2 ? "s" : "");
			question = "Êtes-vous sûr de vouloir décaler de " + nbdecal + " unité" + pluriel 
				+ " les pages " + from + " à " + to 
				+ " dans « " + document + " » ?";
			OO.ui.confirm(question).done(function(confirmed) {
				if(confirmed) {
					// Les données ont été validées, donc on peut fermer le formulaire
					form_dialog.close();

					// Le renommage va de la dernière à la première page si le décalage est positif,
					// et inversement
					premier = (nbdecal > 0 ? to : from);
					dernier = (nbdecal > 0 ? from : to);
					
					// Fonction asynchrone, rend la main tout de suite
					copiePages({
						page_base: page_base,
						premier: premier,
						dernier: dernier,
						nbdecal: nbdecal,
						reason: 'Renommage semi-automatisé avec [[' + nom_script + ']]...',
						nbdone: 0
					});
				}
				else {
					alertmsg("Ok, rien n'a été fait.");
				}
			} );
		}
		catch(exc) {
			alertmsg("Erreur : " + exc);
		}		
	}
	
	// Formulaire pour entrer les données
	function form() {
		function MyDialog( config ) {
			MyDialog.parent.call( this, config );
		}
		OO.inheritClass( MyDialog, OO.ui.Dialog );
		MyDialog.static.name = 'myDialog';
		MyDialog.prototype.initialize = function () {
			MyDialog.parent.prototype.initialize.call(this);
			this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } );
			this.content.$element.append("<p><b>Attention</b> : ce script est purement expérimental.</p><p>Cet outil récupère la couche texte d'un ensemble de pages"
				+ " et l'injecte dans les pages situées plus loin ou moins loin dans le même livre. "
				+ "Les pages d'origine et de destination ne doivent pas avoir encore été créées"
				+ " (si la page d'origine existe, il convient plutôt de faire un renommage).</p>");
			dialog = this;

			documentLabel = new OO.ui.LabelWidget({ label: 'Nom du document DjVu (ex. Livre:Mon livre.djvu)' });
			this.content.$element.append(documentLabel.$element);
			var livreInput = new OO.ui.TextInputWidget({ });
			this.content.$element.append(livreInput.$element);

			fromLabel = new OO.ui.LabelWidget({ label: 'Première page à décaler (entier > 0)' });
			this.content.$element.append(fromLabel.$element);
			var fromInput = new OO.ui.TextInputWidget({ validate:'integer' });
			this.content.$element.append(fromInput.$element);
			
			toLabel = new OO.ui.LabelWidget({ label: 'Dernière page à décaler (entier > 0)' });
			this.content.$element.append(toLabel.$element);
			var toInput = new OO.ui.TextInputWidget({ validate:'integer' });
			this.content.$element.append(toInput.$element);

			pasLabel = new OO.ui.LabelWidget({ label: 'Nombre d\'unités de décalage (entier positif ou négatif)' });
			this.content.$element.append(pasLabel.$element);
			var pasInput = new OO.ui.TextInputWidget({ });
			this.content.$element.append(pasInput.$element);

			var validerButton = new OO.ui.ButtonInputWidget({
				label: 'Valider',
				icon: 'check',
				value: 'check'
			});
			validerButton.on('click', function() {
				doit(dialog, livreInput.value.trim(), fromInput.value, toInput.value, pasInput.value);
			});
			this.content.$element.append(validerButton.$element);
			var cancelButton = new OO.ui.ButtonInputWidget({
				label: 'Annuler',
				icon: 'cancel',
				value: 'cancel'
			});
			cancelButton.on('click', function() {
				dialog.close();
			});
			this.content.$element.append(cancelButton.$element);
			this.$body.append(this.content.$element);
		};
		MyDialog.prototype.getBodyHeight = function () {
			return this.content.$element.outerHeight( true );
		};
		var myDialog = new MyDialog( {
			size: 'medium'
		} );
		var windowManager = new OO.ui.WindowManager();
		$( document.body ).append(windowManager.$element);
		windowManager.addWindows([myDialog]);
		windowManager.openWindow(myDialog);	
	}

	$('#sd-recopier').on('click', function(e) {
		// Code exécuté quand on clique sur la commande
		e.preventDefault();
		try {
			form();
		}
		catch(exc) {
			alert("Erreur : " + exc);
		}
	});
});