Utente:Titore/CatChangesViewer.js
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);
});