Utente:Titore/CatChangesViewer.js

Da Wikipedia, l'enciclopedia libera.
Vai alla navigazione Vai alla ricerca

Questa pagina definisce alcuni parametri di aspetto e comportamento generale di tutte le pagine. Per personalizzarli vedi Aiuto:Stile utente.


Nota: dopo aver salvato è necessario pulire la cache del proprio browser per vedere i cambiamenti (per le pagine globali è comunque necessario attendere qualche minuto). Per Mozilla / Firefox / Safari: fare clic su Ricarica tenendo premuto il tasto delle maiuscole, oppure premere Ctrl-F5 o Ctrl-R (Command-R su Mac); per Chrome: premere Ctrl-Shift-R (Command-Shift-R su un Mac); per Konqueror: premere il pulsante Ricarica o il tasto F5; per Opera può essere necessario svuotare completamente la cache dal menù Strumenti → Preferenze; per Internet Explorer: mantenere premuto il tasto Ctrl mentre si preme il pulsante Aggiorna o premere Ctrl-F5.

/**
 * da [[en:User:Nardog/CatChangesViewer.js]]
* Elenca le recenti aggiunte/rimozioni in una categoria
 */
//

mw.config.get('wgNamespaceNumber') === 14 &&
mw.config.get('wgAction') === 'view' &&
$.when($.ready, mw.loader.using([
	'mediawiki.api', 'mediawiki.util', 'oojs-ui-widgets', 'mediawiki.widgets',
	'mediawiki.widgets.UserInputWidget', 'mediawiki.widgets.datetime',
	'oojs-ui.styles.icons-interactions', 'oojs-ui.styles.icons-movement',
	'mediawiki.interface.helpers.styles'
])).then(function catChangesViewer() {
	mw.loader.addStyleTag('.catchangesviewer .oo-ui-numberInputWidget{width:4em} .catchangesviewer .oo-ui-numberInputWidget input{text-align:center} .catchangesviewer .oo-ui-menuSelectWidget, .catchangesviewer .mw-widgets-datetime-dateTimeInputWidget{width:min-content} .catchangesviewer .mw-widget-userInputWidget{width:8em} .catchangesviewer .oo-ui-fieldLayout-align-inline{vertical-align:top} .catchangesviewer-table{white-space:nowrap} .catchangesviewer-addition{background:#e6ffe6} .catchangesviewer-removal{background:#ffe6e6} .catchangesviewer-table td:empty::after{content:"\\00a0"}');
	
	let defLimit = window.catchangesviewerDefaultLimit || 50;
	let perPageNum = window.catchangesviewerChangesPerPage || 20;
	let limitInput = new OO.ui.NumberInputWidget({
		required: true,
		min: 1,
		max: 500,
		value: defLimit,
		showButtons: false,
		title: 'Number of changes to load (1–500)'
	}).setIndicator();
	
	let filterOptions = {
		'!anon': new OO.ui.MenuOptionWidget({
			data: { incompatibleWith: 'anon' },
			label: 'No IPs',
			icon: 'none'
		}),
		anon: new OO.ui.MenuOptionWidget({
			data: { incompatibleWith: '!anon' },
			label: 'IPs only',
			icon: 'none'
		}),
		'!bot': new OO.ui.MenuOptionWidget({
			data: { incompatibleWith: 'bot' },
			label: 'No bots',
			icon: 'none'
		}),
		bot: new OO.ui.MenuOptionWidget({
			data: { incompatibleWith: '!bot' },
			label: 'Bots only',
			icon: 'none'
		}),
		rcuser: new OO.ui.MenuOptionWidget({
			data: { param: 'rcuser', incompatibleWith: 'rcexcludeuser', input: 'user' },
			label: 'This user:',
			icon: 'none'
		}),
		rcexcludeuser: new OO.ui.MenuOptionWidget({
			data: { param: 'rcexcludeuser', incompatibleWith: 'rcuser', input: 'user' },
			label: 'Not this user:',
			icon: 'none'
		}),
		rcstart: new OO.ui.MenuOptionWidget({
			data: { param: 'rcstart', input: 'until' },
			label: 'Until:',
			icon: 'none'
		})
	};
	let now = Date.now();
	let filterInputs = {
		user: new mw.widgets.UserInputWidget({
			placeholder: 'User'
		}).toggle(),
		until: new mw.widgets.datetime.DateTimeInputWidget({
			min: new Date(now - 2592000000), // 30 days ago
			clearable: false
		}).toggle()
	};
	let filtersButton = new OO.ui.ButtonMenuSelectWidget({
		icon: 'funnel',
		title: 'Filters',
		menu: { items: Object.values(filterOptions) }
	});
	let filtersMenu = filtersButton.getMenu();
	let filtersLayout = new OO.ui.HorizontalLayout({
		items: [filtersButton, filterInputs.user, filterInputs.until]
	});
	
	let button = new OO.ui.ButtonInputWidget({
		label: 'Cerca',
		flags: ['primary', 'progressive'],
		type: 'submit'
	});
	let refreshButton = new OO.ui.ButtonWidget({
		icon: 'reload',
		title: 'Load new',
		disabled: true
	});
	let buttonsLayout = new OO.ui.HorizontalLayout({
		items: [button, refreshButton]
	});
	
	let form = new OO.ui.FormLayout({
		items: [limitInput, filtersLayout, buttonsLayout],
		classes: ['oo-ui-horizontalLayout']
	});
	
	let $div = $('<div>').addClass('catchangesviewer').append(form.$element);
	let $table, $tbody, $error = $('<div>');
	
	let navLabel = new OO.ui.LabelWidget();
	let firstButton = new OO.ui.ButtonWidget({
		icon: 'first',
		title: 'Newest ' + perPageNum
	});
	let prevButton = new OO.ui.ButtonWidget({
		icon: 'previous',
		title: 'Newer ' + perPageNum
	});
	let nextButton = new OO.ui.ButtonWidget({
		icon: 'next',
		title: 'Older ' + perPageNum
	});
	let lastButton = new OO.ui.ButtonWidget({
		icon: 'last',
		title: 'Oldest ' + perPageNum
	});
	let hideAdditionsCheckbox = new OO.ui.CheckboxInputWidget();
	let hideRemovalsCheckbox = new OO.ui.CheckboxInputWidget();
	let hideDuplicatesCheckbox = new OO.ui.CheckboxInputWidget();
	let hideLayout = new OO.ui.HorizontalLayout({
		items: [
			new OO.ui.LabelWidget({ label: 'Nascondi:' }),
			new OO.ui.FieldLayout(
				hideAdditionsCheckbox,
				{ label: 'Aggiunte', align: 'inline' }
			),
			new OO.ui.FieldLayout(
				hideRemovalsCheckbox,
				{ label: 'Rimozioni', align: 'inline' }
			),
			new OO.ui.FieldLayout(
				hideDuplicatesCheckbox,
				{ label: 'Duplicati', align: 'inline' }
			)
		]
	});
	let navLayout = new OO.ui.HorizontalLayout({
		items: [
			navLabel,
			new OO.ui.ButtonGroupWidget({
				items: [firstButton, prevButton, nextButton, lastButton]
			}),
			hideLayout
		]
	}).toggle();
	
	let args = {
		action: 'query',
		list: 'recentchanges',
		rctype: 'categorize',
		rctitle: mw.config.get('wgPageName'),
		rcprop: 'ids|timestamp|comment|user|flags',
		formatversion: 2
	};
	let prevArgs, modified = new Set(), prevLabel, prevDisabled;
	let setArg = (k, v) => {
		if (v) {
			args[k] = v;
		} else {
			delete args[k];
		}
		if (prevArgs) {
			if (args[k] == prevArgs[k]) {
				modified.delete(k);
			} else {
				modified.add(k);
			}
			if (modified.size) {
				button.setLabel('Search').setDisabled(false);
			} else {
				button.setLabel(prevLabel).setDisabled(prevDisabled);
			}
		}
	};
	filterInputs.user.on('change', v => {
		setArg(filterOptions.rcuser.getIcon() === 'check' ? 'rcuser' : 'rcexcludeuser', v);
	});
	filterInputs.until.on('change', setArg, ['rcstart']);
	
	filtersMenu.on('choose', option => {
		let data = option.getData();
		if (option.getIcon() === 'none') {
			option.setIcon('check');
			if (data.incompatibleWith) filterOptions[data.incompatibleWith].setIcon('none');
			filtersButton.setIndicator('required');
			if (data.input) {
				filterInputs[data.input].toggle(true);
				if (data.incompatibleWith) setArg(data.incompatibleWith);
				setArg(data.param, filterInputs[data.input].getValue());
			}
		} else {
			option.setIcon('none');
			if (!filtersMenu.getItems().some(item => item.getIcon() === 'check')) {
				filtersButton.setIndicator();
			}
			if (data.input) {
				filterInputs[data.input].toggle(false);
				setArg(data.param);
			}
		}
		if (!data.input) {
			setArg(
				'rcshow',
				Object.keys(filterOptions).filter(k => {
					let o = filterOptions[k];
					return o.getIcon() === 'check' && !o.getData().input;
				}).join('|')
			);
		}
	});
	
	let setDisabledAll = disabled => {
		[
			limitInput, filtersButton, filtersMenu, filterInputs.user,
			filterInputs.until, button, refreshButton, firstButton, prevButton,
			nextButton, lastButton, hideAdditionsCheckbox, hideRemovalsCheckbox,
			hideDuplicatesCheckbox
		].forEach(widget => {
			widget.setDisabled(disabled);
		});
		if (!disabled) resetNavButtons();
	};
	
	let api, recentchanges = [], additions = [], removals = [], newest = {}, refArgs;
	let load = isRefresh => {
		if (isRefresh) {
			prevDisabled = button.isDisabled();
			if (!refArgs) refArgs = Object.assign({ rcdir: 'newer' }, prevArgs);
			refArgs.rclimit = limitInput.getNumericValue() + 1;
			refArgs.rccontinue = recentchanges[0].timestamp.replace(/\D/g, '') + '|' + recentchanges[0].revid;
		} else {
			prevLabel = button.getLabel();
			button.setLabel('Caricamento...');
			args.rclimit = limitInput.getNumericValue();
			if (modified.size) {
				delete args.rccontinue;
				recentchanges = [];
				additions = [];
				removals = [];
				newest = {};
				refArgs = null;
				$table.detach();
				$tbody.empty();
				navLayout.toggle(false);
				modified.clear();
			}
			prevArgs = Object.assign({}, args);
		}
		setDisabledAll(true);
		$error.empty();
		if (!api) api = new mw.Api({
			ajax: { headers: { 'Api-User-Agent': 'CatChangesViewer (https://en.wikipedia.org/wiki/User:Nardog/CatChangesViewer)' } }
		});
		api.get(isRefresh ? refArgs : args).always((response, errorObj) => {
			setDisabledAll(false);
			if (isRefresh) button.setDisabled(prevDisabled);
			let errorMsg = ((errorObj || {}).error || {}).info;
			if (!response || typeof response === 'string' || errorMsg) {
				button.setLabel(prevLabel);
				$error.text(errorMsg ? 'Error: ' + errorMsg : 'Unknown error').appendTo($div);
				return;
			}
			let newRc = ((response || {}).query || {}).recentchanges || [];
			let rccontinue = ((response || {}).continue || {}).rccontinue;
			if (!isRefresh) {
				args.rccontinue = rccontinue;
				if (rccontinue) {
					button.setLabel('Load more');
				} else if (response.batchcomplete) {
					let rcCount = recentchanges.length + newRc.length;
					button.setLabel(rcCount ? 'No more results' : 'No results').setDisabled(true);
				}
				prevLabel = button.getLabel();
				prevDisabled = button.isDisabled();
			}
			processRc(newRc, isRefresh);
			if (isRefresh && !rccontinue || !isRefresh && !prevArgs.rccontinue) {
				refreshButton.setDisabled(true);
				if (!prevArgs.rcstart || prevArgs.rcstart > new Date().toISOString()) {
					setTimeout(() => {
						refreshButton.setDisabled(false);
					}, 5000);
				}
			}
		});
	};
	
	let msgKeys = mw.config.get('wgContentLanguage') === 'en' ? [] : [
		'recentchanges-page-added-to-category',
		'recentchanges-page-added-to-category-bundled',
		'recentchanges-page-removed-from-category',
		'recentchanges-page-removed-from-category-bundled'
	];
	let addedKeys = msgKeys.slice(0, 2), removedKeys = msgKeys.slice(2);
	let processRc = (newRc, isRefresh) => {
		if (isRefresh && (newRc[0] || {}).revid === recentchanges[0].revid) newRc.shift();
		if (!newRc.length) return;
		
		api.loadMessagesIfMissing(msgKeys).always(() => {
			let method = isRefresh ? 'unshift' : 'push';
			newRc.forEach(rc => {
				if (!rc.comment) return;
				let page = rc.comment.match(/\[\[:?([^\]]+)\]\]/)[1];
				
				let action, actionClass;
				if (rc.comment.includes(']] added to category')) {
					action = true;
				} else if (rc.comment.includes(']] removed from category')) {
					action = false;
				} else if (addedKeys.some(key => rc.comment === mw.msg(key, page))) {
					action = true;
				} else if (removedKeys.some(key => rc.comment === mw.msg(key, page))) {
					action = false;
				}
				if (action === true) {
					action = '+';
					actionClass = 'catchangesviewer-addition';
					additions[method](rc);
				} else if (action === false) {
					action = '−';
					actionClass = 'catchangesviewer-removal';
					removals[method](rc);
				} else {
					action = '?';
				}
				
				rc.$row = $('<tr>').addClass(actionClass).append(
					$('<td>').text(action),
					$('<td>').append(
						$('<a>')
							.attr('href', mw.util.getUrl(page, { oldid: rc.revid }))
							.text(new Date(rc.timestamp)
									.toLocaleString('it-IT',{
										timeZone: 'Europe/Rome',
										dateStyle: 'medium',
										timeStyle: 'short'
									})
									.split(', ').reverse().join(', ')
							),
						' ',
						$('<span>').addClass('mw-changeslist-links').append(
							$('<a>')
								.attr('href', mw.util.getUrl(page, { diff: rc.revid }))
								.text('diff')
								.wrap('<span>').parent(),
							$('<a>')
								.attr('href', mw.util.getUrl(page, { curid: rc.pageid, action: 'history' }))
								.text('cron')
								.wrap('<span>').parent()
						)
					),
					$('<td>').append(
						$('<a>').attr('href', mw.util.getUrl(page)).text(page)
					),
					$('<td>').append(
						$('<a>')
							.attr('href', mw.util.getUrl((rc.anon ? 'Special:Contributions/' : 'User:') + rc.user))
							.text(rc.user),
						' ',
						$('<span>').addClass('mw-changeslist-links').append(
							$('<a>')
								.attr('href', mw.util.getUrl('Discussioni utente:' + rc.user))
								.text('discussione')
								.wrap('<span>').parent(),
							!rc.anon && $('<a>')
								.attr('href', mw.util.getUrl('Special:Contributions/' + rc.user))
								.text('contributi')
								.wrap('<span>').parent()
						)
					),
					$('<td>').text(rc.bot ? 'Sì' : 'No')
				);
				if (newest.hasOwnProperty(page)) {
					if (isRefresh) {
						newest[page].duplicate = true;
						newest[page] = rc;
					} else {
						rc.duplicate = true;
					}
				} else {
					newest[page] = rc;
				}
				recentchanges[method](rc);
			});
			initializeNavigation();
		});
	};
	
	let currentPage = 0, pageCount, visibleRows;
	let initializeNavigation = () => {
		let rcToShow = hideAdditionsCheckbox.isSelected() ? removals :
			hideRemovalsCheckbox.isSelected() ? additions :
			recentchanges;
		if (hideDuplicatesCheckbox.isSelected()) {
			rcToShow = rcToShow.filter(rc => !rc.duplicate);
		}
		visibleRows = rcToShow.map(rc => rc.$row[0]);
		pageCount = Math.ceil(visibleRows.length / perPageNum) || 1;
		let z = recentchanges.length > perPageNum
			? perPageNum * pageCount - visibleRows.length
			: recentchanges.length - visibleRows.length;
		for (let i = 0, j; i < z; i++) {
			let $row = $('<tr>');
			for (j = 0; j < 5; j++) $('<td>').appendTo($row);
			visibleRows.push($row[0]);
		}
		if (!$table) {
			$tbody = $('<tbody>');
			$table = $('<table>').addClass('wikitable catchangesviewer-table').append(
				$('<tr>').append(
					$('<th>').text('±'),
					$('<th>').text('Data'),
					$('<th>').text('Pagina'),
					$('<th>').text('Utente'),
					$('<th>').text('Bot')
				).wrap('<thead>').parent(),
				$tbody
			);
		}
		setPage();
		$table.prependTo($div);
		if (!navLayout.isVisible()) navLayout.toggle(true).$element.insertAfter($table);
	};
	let setPage = increment => {
		if (pageCount > 1) {
			if (increment === false) {
				currentPage = 0;
			} else if (increment === true) {
				currentPage = pageCount - 1;
			} else if (increment) {
				currentPage += increment;
				if (currentPage < 0) currentPage = pageCount - 1;
				if (currentPage > pageCount - 1) currentPage = 0;
			} else {
				if (currentPage > pageCount - 1) currentPage = pageCount - 1;
			}
		} else {
			currentPage = 0;
		}
		$tbody.empty();
		let start = currentPage * perPageNum;
		$tbody.append(visibleRows.slice(start, start + perPageNum));
		navLabel.setLabel(currentPage + 1 + ' / ' + pageCount);
		resetNavButtons();
	};
	let resetNavButtons = () => {
		firstButton.setDisabled(currentPage === 0);
		prevButton.setDisabled(pageCount < 2);
		nextButton.setDisabled(pageCount < 2);
		lastButton.setDisabled(currentPage === pageCount - 1);
	};
	
	firstButton.on('click', setPage, [false]);
	prevButton.on('click', setPage, [-1]);
	nextButton.on('click', setPage, [1]);
	lastButton.on('click', setPage, [true]);
	
	hideAdditionsCheckbox.on('change', selected => {
		if (selected) hideRemovalsCheckbox.setSelected(false);
		initializeNavigation();
	});
	hideRemovalsCheckbox.on('change', selected => {
		if (selected) hideAdditionsCheckbox.setSelected(false);
		initializeNavigation();
	});
	hideDuplicatesCheckbox.on('change', initializeNavigation);
	
	button.on('click', load);
	refreshButton.on('click', load, [true]);
	
	$('.mw-category-generated').first().before($('<h2>').text('Modifiche recenti'), $div);
});