// This script led to [[:phab:T308364]] being filed.
/* jshint esversion: 10, maxerr: 9999, unused: true, quotmark: single */
$(() => {
const spn = (mw.config.get('wgCanonicalSpecialPageName') || '').toLowerCase();
const lc = str => str.toLowerCase();
const switches = function (cases, def) {
for (const i in cases) {
if (i.toLowerCase() === spn) {
return cases[i];
}
}
return def;
};
// Main functions
const linktoggle = function () {
window.ajaxloaderloading = !window.ajaxloaderloading;
};
const spinner = function () {
const $l = $('<div>').attr('class', 'ajaxloader-loader');
for (let i = 0; i < 12; i++) {
$l.append(
$('<div>')
.attr('class', 'ajaxloader-loader-items')
.css({
animation: 'ajaxloader-loader 1.2s linear infinite',
transform: `rotate(${i * 30}deg)`,
'animation-delay': Math.round((-1.1 + i * 0.1) * 10) / 10 + 's'
})
);
}
return $('<div>')
.attr({
class: 'ajaxloader-loader-wrapper',
id: 'ajaxloader-loader'
})
.append($l);
};
const init = function (object) {
const {links, linkswrapper, linkextend, main, parent, preload, preupdate} = object;
const updateWrapper =
object.update !== 'unwrapped' ?
(linkswrapper || links) &&
function (content) {
if (preupdate) {
preupdate();
}
$(linkswrapper || links).each(function (index) {
$(this).replaceWith($(linkswrapper || links, content)[index]);
});
}
: function (content) {
let $links = [
$(parent || '#mw-content-text').clone(),
$(parent || '#mw-content-text', content).clone()
];
$links = $links.map($el => {
$el.find('*').not('a').remove();
$el.html(
$el
.html()
.trim()
.replace(/\s*title=".*?(?<!\\)"(\s*)/g, '$1')
.replace(/.*?(.+)\s*\1.*?/, '$1')
);
return $el;
});
$(links).each(function () {
$(this).prop(
'outerHTML',
$(this)
.prop('outerHTML')
.replace(/\s*title=".*?"(\s*)/g, '$1')
);
});
for (const _ of [0, 1]) {
$('#mw-content-text').html((_, oldHtml) => oldHtml.replace($links[0].html(), $links[1].html()));
}
};
if (!links) {
console.warn('No links.');
return;
}
const update = function (response) {
updateWrapper(response);
$(main).replaceWith($(main, response));
if (preload) {
preload();
}
mw.hook('wikipage.content').fire($(main));
};
const initialHtml = document.documentElement.outerHTML;
// handle navigating between history items pushed by this script
window.addEventListener('popstate', event => {
update(event?.state?.response ?? initialHtml);
});
$('body').on('click', links, function (e) {
e.preventDefault();
if (window.ajaxloaderloading) {
return;
}
linktoggle();
const $spinner = spinner();
$(main).hide().after($spinner);
const link = new URL($(this).prop('href'));
if (linkextend) {
Object.entries(linkextend).forEach(([key, value]) => {
link.searchParams.set(key, value);
});
}
$.ajax({
url: link.toString(),
success: function (response) {
$spinner.remove();
linktoggle();
update(response);
window.history.___pushState({response: response}, '', link); // add new URL to history/urlbar
},
error: function () {
$spinner.remove();
linktoggle();
$(main).show();
mw.notify('Cannot get pages.', {title: 'AjaxLoader', type: 'warn'});
}
});
});
};
const includes = function (array, element = spn) {
array = array instanceof Array ? array : [array];
return array.some(e => e.toLowerCase() === element.toLowerCase());
};
const join = function (links, parent, separator) {
const s = [];
for (const l of links) {
s.push(`${parent}${separator || ' > a'}${l}`);
}
return s.join(', ');
};
const load = function (server, title) {
mw.loader.load(`//${server}/w/index.php?title=${title}&action=raw&ctype=text/javascript`);
};
// CSS
// For attribution: //loading.io/css (CC0)
const css = `
.ajaxloader-loader-wrapper {
display: block;
margin: 3em 0;
text-align: center;
}
.ajaxloader-loader {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
}
.ajaxloader-loader .ajaxloader-loader-items {
transform-origin: 40px 40px;
}
.ajaxloader-loader .ajaxloader-loader-items::after {
content: ' ';
display: block;
position: absolute;
top: 4px;
left: 36px;
width: 6px;
height: 18px;
border-radius: 20%;
background: #000000;
}
@keyframes ajaxloader-loader {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
`;
mw.loader.addStyleTag(css, document.head.children[0]); // easily overridden
// Data
const data = [
{
name: 'Navlinks inside mw-pager-navigation-bar ([[:phab:T308364]])',
check: function () {
return document.getElementsByClassName('mw-pager-navigation-bar').length > 0;
},
links: join(
['.mw-lastlink', '.mw-firstlink', '.mw-prevlink', '.mw-nextlink', '.mw-numlink'],
'.mw-pager-navigation-bar'
),
linkswrapper: '.mw-pager-navigation-bar',
main:
$('.mw-pager-body').length ? '.mw-pager-body' : (
switches(
{
Log: '.mw-logevent-loglines',
'': '#pagehistory',
AbuseLog: '#mw-content-text > form',
Search: '.mw-search-results-container',
WhatLinksHere: '#mw-whatlinkshere-list',
GlobalUsage: '#mw-globalusage-result'
},
'#mw-content-text ul, #mw-content-text ol'
)
),
preload: function () {
if (includes('NewImages')) {
$('#mw-content-text > ul').before($('.mw-pager-navigation-bar').clone());
}
},
preupdate: function () {
if (includes('NewImages')) {
$($('.mw-pager-navigation-bar')[0]).remove();
}
}
},
{
name: 'Special pages with -nav classes',
check: function () {
return includes(['AllPages', 'PrefixIndex']);
},
links: '.mw-' + spn + '-nav > a',
linkswrapper: '.mw-' + spn + '-nav',
main: '.mw-' + spn + '-body'
},
{
name: 'Abuse filter history',
check: function () {
return spn === lc('AbuseFilter') && $('.mw-abusefilter-history-buttons').length > 0;
},
links: '.mw-abusefilter-history-buttons a.oo-ui-buttonElement-button',
linkswrapper: '.mw-abusefilter-history-buttons',
main: '#mw-content-text > table.wikitable',
preload: function () {
$('#mw-content-text > table.wikitable').before($('.mw-abusefilter-history-buttons').clone());
},
preupdate: function () {
$($('.mw-abusefilter-history-buttons')[0]).remove();
}
},
{
name: 'Modernized special pages with button-like navlinks',
check: function () {
return includes([
'AllMessages',
'ProtectedPages',
'BlockList',
'AutoblockList',
'AbuseFilter',
'ListFiles'
]);
},
links: '.TablePager_nav a',
linkswrapper: '.TablePager_nav',
main: switches({
AllMessages: '#mw-allmessagestable',
ProtectedPages: '.mw-protectedpages',
BlockList: '.mw-blocklist',
AutoblockList: '.mw-blocklist',
AbuseFilter: '.mw-datatable',
ListFiles: '.mw-datatable'
})
},
{
name: 'Contributions',
check: function () {
return includes(['Contributions']);
},
links: '.mw-pager-navigation-bar > a',
linkswrapper: '.mw-pager-navigation-bar',
main: '.mw-pager-body'
},
{
name: 'SearchTranslations',
check: function () {
return includes(['SearchTranslations']);
},
links: '.tux-pagination-links > a',
linkswrapper: '.tux-pagination-links',
main: '.results'
},
{
name: 'Categories',
check: function () {
return mw.config.get('wgNamespaceNumber') === 14;
},
exempt: function () {
load('en.wikipedia.org', 'User:NguoiDungKhongDinhDanh/AjaxCat.js');
}
},
{
name: 'Translatable pages',
check: function () {
return $('ul.mw-pt-languages-list').length;
},
links: '.mw-pt-languages-list a.mw-pt-progress',
linkswrapper: '.mw-pt-languages-list',
main: '#bodyContent'
},
{
name: 'Files',
check: function () {
return mw.config.get('wgNamespaceNumber') === 6;
},
links: join(
['.mw-lastlink', '.mw-firstlink', '.mw-prevlink', '.mw-nextlink', '.mw-numlink'],
'.mw-pager-navigation-bar'
),
linkswrapper: '.mw-pager-navigation-bar',
main: '.filehistory'
}
];
// Init.
for (const i of data) {
if (i.check()) {
console.log(i.name);
if (!i.exempt) {
if (i.preload) {
i.preload();
}
init(i);
} else {
i.exempt();
}
break;
}
}
});