MediaWiki:Common.js: Difference between revisions
Appearance
Content deleted Content added
No edit summary |
No edit summary |
||
| Line 1: | Line 1: | ||
/* ======================================================================== |
|||
/* Erindal Wiki global navigation, fantasy navigation + readable content font loader, fluid cards and live recent changes - v4.8 */ |
|||
ERINDAL WIKI - COMMON.JS v5.0 |
|||
(function () { |
|||
Target: MediaWiki 1.43.x, legacy Vector |
|||
'use strict'; |
|||
The topbar itself is now rendered by MediaWiki:Sidebar. JavaScript only |
|||
function wikiUrl(title) { return mw.util.getUrl(title); } |
|||
adds dropdowns, the remembered sidebar toggle and dynamic homepage data. |
|||
It deliberately does not load fonts or construct the navigation bar. |
|||
======================================================================== */ |
|||
( function () { |
|||
'use strict'; |
|||
if (document.getElementById('ew-google-fonts')) return; |
|||
var |
var sidebarKey = 'erindal-sidebar'; |
||
preconnectGoogle.rel = 'preconnect'; |
|||
preconnectGoogle.href = 'https://fonts.googleapis.com'; |
|||
document.head.appendChild(preconnectGoogle); |
|||
/* Apply the saved state again as a fallback. LocalSettings.php applies the |
|||
var preconnectStatic = document.createElement('link'); |
|||
same class in the document head, before first paint. */ |
|||
preconnectStatic.rel = 'preconnect'; |
|||
try { |
|||
preconnectStatic.href = 'https://fonts.gstatic.com'; |
|||
if ( window.localStorage.getItem( sidebarKey ) === 'collapsed' ) { |
|||
preconnectStatic.crossOrigin = 'anonymous'; |
|||
document. |
document.documentElement.classList.add( 'ew-sidebar-collapsed' ); |
||
} |
|||
} catch ( error ) { |
|||
/* localStorage can be unavailable in strict/private browser modes. */ |
|||
} |
|||
function onReady( callback ) { |
|||
var fonts = document.createElement('link'); |
|||
if ( document.readyState === 'loading' ) { |
|||
fonts.id = 'ew-google-fonts'; |
|||
document.addEventListener( 'DOMContentLoaded', callback, { once: true } ); |
|||
fonts.rel = 'stylesheet'; |
|||
} else { |
|||
fonts.href = 'https://fonts.googleapis.com/css2?family=Alegreya:ital,wght@0,400;0,500;0,600;0,700;1,400&family=Alegreya+SC:wght@400;500;700&family=Almendra+SC&family=Cinzel+Decorative:wght@400;700&display=swap'; |
|||
callback(); |
|||
document.head.appendChild(fonts); |
|||
} |
} |
||
} |
|||
function |
function installSidebarToggle() { |
||
if (document.getElementById('ew- |
if ( !document.getElementById( 'mw-panel' ) || document.getElementById( 'ew-sidebar-toggle' ) ) { |
||
return; |
|||
var bar = document.createElement('div'); |
|||
} |
|||
bar.id = 'ew-global-topbar'; |
|||
var button = document.createElement( 'button' ); |
|||
var links = [ |
|||
button.id = 'ew-sidebar-toggle'; |
|||
button.type = 'button'; |
|||
['World', 'Category:Nations and Realms'], |
|||
['People', 'Category:Characters'], |
|||
['Organizations', 'Category:Organizations'], |
|||
['Magic & Lore', 'Category:Magic and Cosmology'], |
|||
['History', 'Category:History and Timeline'] |
|||
]; |
|||
function updateButton() { |
|||
var nav = document.createElement('nav'); |
|||
var collapsed = document.documentElement.classList.contains( 'ew-sidebar-collapsed' ); |
|||
nav.className = 'ew-global-menu'; |
|||
button.textContent = collapsed ? '\u203a' : '\u2039'; |
|||
links.forEach(function (entry) { |
|||
button.setAttribute( 'aria-expanded', collapsed ? 'false' : 'true' ); |
|||
var a = document.createElement('a'); |
|||
button.setAttribute( 'aria-label', collapsed ? 'Open sidebar' : 'Close sidebar' ); |
|||
a.href = wikiUrl(entry[1]); |
|||
button.title = collapsed ? 'Open sidebar' : 'Close sidebar'; |
|||
a.appendChild(document.createTextNode(entry[0])); |
|||
} |
|||
var arrow = document.createElement('span'); |
|||
arrow.className = 'ew-menu-arrow'; |
|||
arrow.textContent = '⌄'; |
|||
a.appendChild(arrow); |
|||
nav.appendChild(a); |
|||
}); |
|||
button.addEventListener( 'click', function () { |
|||
var search = document.createElement('form'); |
|||
var collapsed = document.documentElement.classList.toggle( 'ew-sidebar-collapsed' ); |
|||
search.className = 'ew-global-search'; |
|||
search.method = 'get'; |
|||
search.action = mw.config.get('wgScriptPath') + '/index.php'; |
|||
var titleField = document.createElement('input'); |
|||
titleField.type = 'hidden'; |
|||
titleField.name = 'title'; |
|||
titleField.value = 'Special:Search'; |
|||
var input = document.createElement('input'); |
|||
input.type = 'search'; |
|||
input.name = 'search'; |
|||
input.placeholder = 'Search the Erindal wiki...'; |
|||
input.setAttribute('aria-label', 'Search the Erindal wiki'); |
|||
var button = document.createElement('button'); |
|||
button.type = 'submit'; |
|||
button.textContent = '⌕'; |
|||
button.setAttribute('aria-label', 'Search'); |
|||
search.appendChild(titleField); |
|||
search.appendChild(input); |
|||
search.appendChild(button); |
|||
try { |
|||
var tools = document.createElement('div'); |
|||
window.localStorage.setItem( sidebarKey, collapsed ? 'collapsed' : 'open' ); |
|||
tools.className = 'ew-global-tools'; |
|||
} catch ( error ) { |
|||
var prefs = document.createElement('a'); |
|||
/* The button still works for this page when storage is blocked. */ |
|||
prefs.className = 'ew-tool-link'; |
|||
} |
|||
prefs.href = wikiUrl('Special:Preferences'); |
|||
prefs.textContent = '⚙'; |
|||
prefs.title = 'Preferences'; |
|||
var user = document.createElement('a'); |
|||
user.className = 'ew-tool-link'; |
|||
var username = mw.config.get('wgUserName'); |
|||
user.href = username ? wikiUrl('User:' + username) : wikiUrl('Special:UserLogin'); |
|||
user.textContent = '♙'; |
|||
user.title = username || 'Log in'; |
|||
tools.appendChild(prefs); |
|||
updateButton(); |
|||
/* Vector's native Edit/Edit source tabs are retained; no duplicate button is added here. */ |
|||
} ); |
|||
updateButton(); |
|||
document.body.appendChild( button ); |
|||
} |
|||
function installTopbarDropdowns() { |
|||
bar.appendChild(nav); |
|||
var topbar = document.getElementById( 'p-erindal-topbar' ); |
|||
bar.appendChild(search); |
|||
if ( !topbar || topbar.dataset.ewEnhanced === '1' ) { |
|||
bar.appendChild(tools); |
|||
return; |
|||
document.body.insertBefore(bar, document.body.firstChild); |
|||
} |
|||
document.documentElement.classList.add('ew-js-ready'); |
|||
} |
|||
topbar.dataset.ewEnhanced = '1'; |
|||
var menus = { |
|||
function activateCategoryCards() { |
|||
'Explore': [ |
|||
document.querySelectorAll('.ew-card[data-ew-page]').forEach(function (card) { |
|||
[ 'Main Page', 'Main Page' ], |
|||
if (card.dataset.ewReady === '1') return; |
|||
[ 'Special:RecentChanges', 'Recent Changes' ], |
|||
card.dataset.ewReady = '1'; |
|||
[ 'Special:AllPages', 'All Pages' ], |
|||
[ 'Special:Categories', 'Categories' ] |
|||
card.setAttribute('tabindex', '0'); |
|||
], |
|||
var destination = card.getAttribute('data-ew-page'); |
|||
'World': [ |
|||
function go() { window.location.href = wikiUrl(destination); } |
|||
[ 'Category:Nations & Realms', 'Nations & Realms' ], |
|||
card.addEventListener('click', go); |
|||
[ 'Category:Races & Peoples', 'Races & Peoples' ], |
|||
card.addEventListener('keydown', function (event) { |
|||
[ 'Category:Locations', 'Locations' ] |
|||
], |
|||
'People': [ |
|||
[ 'Category:Characters', 'Characters' ], |
|||
[ 'Category:Family Lines', 'Family Lines' ] |
|||
], |
|||
'Organizations': [ |
|||
[ 'Category:Organizations', 'All Organizations' ], |
|||
[ 'The Conclave', 'The Conclave' ], |
|||
[ 'Order of the Holy Flame', 'Order of the Holy Flame' ], |
|||
[ 'The Dominion', 'The Dominion' ] |
|||
], |
|||
'Magic & Lore': [ |
|||
[ 'Category:Religion & Deities', 'Religion & Deities' ], |
|||
[ 'Category:Magic & Cosmology', 'Magic & Cosmology' ] |
|||
], |
|||
'History': [ |
|||
[ 'Category:History & Timeline', 'History & Timeline' ], |
|||
[ 'Timeline', 'Timeline' ] |
|||
] |
|||
}; |
|||
Array.prototype.forEach.call( topbar.querySelectorAll( '.mw-list-item' ), function ( item ) { |
|||
var link = item.querySelector( ':scope > a' ); |
|||
if ( !link ) { |
|||
return; |
|||
} |
|||
var label = link.textContent.trim(); |
|||
var entries = menus[ label ]; |
|||
if ( !entries ) { |
|||
return; |
|||
} |
|||
item.classList.add( 'ew-has-dropdown' ); |
|||
var caret = document.createElement( 'button' ); |
|||
caret.type = 'button'; |
|||
caret.className = 'ew-topbar-caret'; |
|||
caret.textContent = '\u2304'; |
|||
caret.setAttribute( 'aria-label', 'Open ' + label + ' menu' ); |
|||
caret.setAttribute( 'aria-expanded', 'false' ); |
|||
var dropdown = document.createElement( 'div' ); |
|||
dropdown.className = 'ew-topbar-dropdown'; |
|||
entries.forEach( function ( entry ) { |
|||
var menuLink = document.createElement( 'a' ); |
|||
menuLink.href = mw.util.getUrl( entry[ 0 ] ); |
|||
menuLink.textContent = entry[ 1 ]; |
|||
dropdown.appendChild( menuLink ); |
|||
} ); |
|||
caret.addEventListener( 'click', function ( event ) { |
|||
event.preventDefault(); |
|||
event.stopPropagation(); |
|||
var willOpen = !item.classList.contains( 'ew-menu-open' ); |
|||
Array.prototype.forEach.call( topbar.querySelectorAll( '.ew-menu-open' ), function ( openItem ) { |
|||
openItem.classList.remove( 'ew-menu-open' ); |
|||
var openCaret = openItem.querySelector( '.ew-topbar-caret' ); |
|||
if ( openCaret ) { |
|||
openCaret.setAttribute( 'aria-expanded', 'false' ); |
|||
} |
|||
} ); |
|||
item.classList.toggle( 'ew-menu-open', willOpen ); |
|||
caret.setAttribute( 'aria-expanded', willOpen ? 'true' : 'false' ); |
|||
} ); |
|||
item.appendChild( caret ); |
|||
item.appendChild( dropdown ); |
|||
} ); |
|||
document.addEventListener( 'click', function () { |
|||
Array.prototype.forEach.call( topbar.querySelectorAll( '.ew-menu-open' ), function ( item ) { |
|||
item.classList.remove( 'ew-menu-open' ); |
|||
var caret = item.querySelector( '.ew-topbar-caret' ); |
|||
if ( caret ) { |
|||
caret.setAttribute( 'aria-expanded', 'false' ); |
|||
} |
|||
} ); |
|||
} ); |
|||
document.addEventListener( 'keydown', function ( event ) { |
|||
if ( event.key === 'Escape' ) { |
|||
Array.prototype.forEach.call( topbar.querySelectorAll( '.ew-menu-open' ), function ( item ) { |
|||
item.classList.remove( 'ew-menu-open' ); |
|||
var caret = item.querySelector( '.ew-topbar-caret' ); |
|||
if ( caret ) { |
|||
caret.setAttribute( 'aria-expanded', 'false' ); |
|||
} |
|||
} ); |
|||
} |
|||
} ); |
|||
} |
|||
function makeHomepageCardsClickable() { |
|||
Array.prototype.forEach.call( document.querySelectorAll( '.ew-card' ), function ( card ) { |
|||
var link = card.querySelector( 'a[href]' ); |
|||
if ( !link ) { |
|||
return; |
|||
} |
|||
card.setAttribute( 'tabindex', '0' ); |
|||
card.setAttribute( 'role', 'link' ); |
|||
card.addEventListener( 'click', function ( event ) { |
|||
if ( !event.target.closest( 'a' ) ) { |
|||
window.location.href = link.href; |
|||
} |
|||
} ); |
|||
card.addEventListener( 'keydown', function ( event ) { |
|||
if ( event.key === 'Enter' || event.key === ' ' ) { |
|||
event.preventDefault(); |
|||
window.location.href = link.href; |
|||
} |
|||
} ); |
|||
} ); |
|||
} |
|||
function loadRecentChanges() { |
|||
var loading = document.querySelector( '.ew-recent-loading' ); |
|||
if ( !loading ) { |
|||
return; |
|||
} |
} |
||
}); |
|||
}); |
|||
} |
|||
var api = new mw.Api(); |
|||
function loadRecentChanges() { |
|||
api.get( { |
|||
var target = document.getElementById('ew-recent-list'); |
|||
action: 'query', |
|||
if (!target) return; |
|||
list: 'recentchanges', |
|||
var api = new mw.Api(); |
|||
rcnamespace: 0, |
|||
api.get({ |
|||
rcshow: '!bot', |
|||
rcprop: 'title|timestamp|user', |
|||
rctype: 'edit|new', |
|||
rclimit: 5, |
rclimit: 5, |
||
formatversion: 2 |
|||
} ).then( function ( data ) { |
|||
formatversion: 2 |
|||
var changes = data && data.query && data.query.recentchanges ? data.query.recentchanges : []; |
|||
}).done(function (data) { |
|||
loading.textContent = ''; |
|||
var rows = data && data.query && data.query.recentchanges ? data.query.recentchanges : []; |
|||
target.innerHTML = ''; |
|||
if (!rows.length) { |
|||
target.innerHTML = '<div class="ew-recent-loading">No article edits yet.</div>'; |
|||
return; |
|||
} |
|||
rows.forEach(function (item) { |
|||
var row = document.createElement('div'); |
|||
row.className = 'ew-recent-row'; |
|||
var icon = document.createElement('span'); |
|||
icon.className = 'ew-recent-icon'; |
|||
icon.textContent = '◆'; |
|||
var copy = document.createElement('div'); |
|||
var link = document.createElement('a'); |
|||
link.href = wikiUrl(item.title); |
|||
link.textContent = item.title; |
|||
var small = document.createElement('small'); |
|||
var date = new Date(item.timestamp); |
|||
small.textContent = 'Edited ' + date.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); |
|||
copy.appendChild(link); |
|||
copy.appendChild(small); |
|||
row.appendChild(icon); |
|||
row.appendChild(copy); |
|||
target.appendChild(row); |
|||
}); |
|||
}).fail(function () { |
|||
target.innerHTML = '<div class="ew-recent-loading">Recent changes unavailable.</div>'; |
|||
}); |
|||
} |
|||
if ( !changes.length ) { |
|||
/* Callback form is compatible with the ResourceLoader API used by MW 1.43. */ |
|||
loading.textContent = 'No recent article changes.'; |
|||
mw.loader.using(['mediawiki.util', 'mediawiki.api'], function () { |
|||
return; |
|||
if (document.readyState === 'loading') { |
|||
} |
|||
document.addEventListener('DOMContentLoaded', function () { |
|||
loadErindalFonts(); |
|||
changes.forEach( function ( change ) { |
|||
buildTopbar(); |
|||
var row = document.createElement( 'div' ); |
|||
activateCategoryCards(); |
|||
row.className = 'ew-recent-row'; |
|||
loadRecentChanges(); |
|||
}, { once: true }); |
|||
var icon = document.createElement( 'span' ); |
|||
} else { |
|||
icon.className = 'ew-recent-icon'; |
|||
loadErindalFonts(); |
|||
icon.textContent = change.title.slice( 0, 2 ).toUpperCase(); |
|||
buildTopbar(); |
|||
activateCategoryCards(); |
|||
var copy = document.createElement( 'span' ); |
|||
loadRecentChanges(); |
|||
var link = document.createElement( 'a' ); |
|||
link.href = mw.util.getUrl( change.title ); |
|||
link.textContent = change.title; |
|||
var detail = document.createElement( 'small' ); |
|||
var date = new Date( change.timestamp ); |
|||
detail.textContent = date.toLocaleDateString() + ( change.user ? ' - ' + change.user : '' ); |
|||
copy.appendChild( link ); |
|||
copy.appendChild( detail ); |
|||
row.appendChild( icon ); |
|||
row.appendChild( copy ); |
|||
loading.appendChild( row ); |
|||
} ); |
|||
} ).catch( function () { |
|||
loading.textContent = 'Recent changes could not be loaded.'; |
|||
} ); |
|||
} |
} |
||
}); |
|||
mw.loader.using( [ 'mediawiki.api', 'mediawiki.util' ] ).then( function () { |
|||
}()); |
|||
onReady( function () { |
|||
installSidebarToggle(); |
|||
installTopbarDropdowns(); |
|||
makeHomepageCardsClickable(); |
|||
loadRecentChanges(); |
|||
} ); |
|||
} ); |
|||
}() ); |
|||
Revision as of 22:05, 16 August 2026
/* ========================================================================
ERINDAL WIKI - COMMON.JS v5.0
Target: MediaWiki 1.43.x, legacy Vector
The topbar itself is now rendered by MediaWiki:Sidebar. JavaScript only
adds dropdowns, the remembered sidebar toggle and dynamic homepage data.
It deliberately does not load fonts or construct the navigation bar.
======================================================================== */
( function () {
'use strict';
var sidebarKey = 'erindal-sidebar';
/* Apply the saved state again as a fallback. LocalSettings.php applies the
same class in the document head, before first paint. */
try {
if ( window.localStorage.getItem( sidebarKey ) === 'collapsed' ) {
document.documentElement.classList.add( 'ew-sidebar-collapsed' );
}
} catch ( error ) {
/* localStorage can be unavailable in strict/private browser modes. */
}
function onReady( callback ) {
if ( document.readyState === 'loading' ) {
document.addEventListener( 'DOMContentLoaded', callback, { once: true } );
} else {
callback();
}
}
function installSidebarToggle() {
if ( !document.getElementById( 'mw-panel' ) || document.getElementById( 'ew-sidebar-toggle' ) ) {
return;
}
var button = document.createElement( 'button' );
button.id = 'ew-sidebar-toggle';
button.type = 'button';
function updateButton() {
var collapsed = document.documentElement.classList.contains( 'ew-sidebar-collapsed' );
button.textContent = collapsed ? '\u203a' : '\u2039';
button.setAttribute( 'aria-expanded', collapsed ? 'false' : 'true' );
button.setAttribute( 'aria-label', collapsed ? 'Open sidebar' : 'Close sidebar' );
button.title = collapsed ? 'Open sidebar' : 'Close sidebar';
}
button.addEventListener( 'click', function () {
var collapsed = document.documentElement.classList.toggle( 'ew-sidebar-collapsed' );
try {
window.localStorage.setItem( sidebarKey, collapsed ? 'collapsed' : 'open' );
} catch ( error ) {
/* The button still works for this page when storage is blocked. */
}
updateButton();
} );
updateButton();
document.body.appendChild( button );
}
function installTopbarDropdowns() {
var topbar = document.getElementById( 'p-erindal-topbar' );
if ( !topbar || topbar.dataset.ewEnhanced === '1' ) {
return;
}
topbar.dataset.ewEnhanced = '1';
var menus = {
'Explore': [
[ 'Main Page', 'Main Page' ],
[ 'Special:RecentChanges', 'Recent Changes' ],
[ 'Special:AllPages', 'All Pages' ],
[ 'Special:Categories', 'Categories' ]
],
'World': [
[ 'Category:Nations & Realms', 'Nations & Realms' ],
[ 'Category:Races & Peoples', 'Races & Peoples' ],
[ 'Category:Locations', 'Locations' ]
],
'People': [
[ 'Category:Characters', 'Characters' ],
[ 'Category:Family Lines', 'Family Lines' ]
],
'Organizations': [
[ 'Category:Organizations', 'All Organizations' ],
[ 'The Conclave', 'The Conclave' ],
[ 'Order of the Holy Flame', 'Order of the Holy Flame' ],
[ 'The Dominion', 'The Dominion' ]
],
'Magic & Lore': [
[ 'Category:Religion & Deities', 'Religion & Deities' ],
[ 'Category:Magic & Cosmology', 'Magic & Cosmology' ]
],
'History': [
[ 'Category:History & Timeline', 'History & Timeline' ],
[ 'Timeline', 'Timeline' ]
]
};
Array.prototype.forEach.call( topbar.querySelectorAll( '.mw-list-item' ), function ( item ) {
var link = item.querySelector( ':scope > a' );
if ( !link ) {
return;
}
var label = link.textContent.trim();
var entries = menus[ label ];
if ( !entries ) {
return;
}
item.classList.add( 'ew-has-dropdown' );
var caret = document.createElement( 'button' );
caret.type = 'button';
caret.className = 'ew-topbar-caret';
caret.textContent = '\u2304';
caret.setAttribute( 'aria-label', 'Open ' + label + ' menu' );
caret.setAttribute( 'aria-expanded', 'false' );
var dropdown = document.createElement( 'div' );
dropdown.className = 'ew-topbar-dropdown';
entries.forEach( function ( entry ) {
var menuLink = document.createElement( 'a' );
menuLink.href = mw.util.getUrl( entry[ 0 ] );
menuLink.textContent = entry[ 1 ];
dropdown.appendChild( menuLink );
} );
caret.addEventListener( 'click', function ( event ) {
event.preventDefault();
event.stopPropagation();
var willOpen = !item.classList.contains( 'ew-menu-open' );
Array.prototype.forEach.call( topbar.querySelectorAll( '.ew-menu-open' ), function ( openItem ) {
openItem.classList.remove( 'ew-menu-open' );
var openCaret = openItem.querySelector( '.ew-topbar-caret' );
if ( openCaret ) {
openCaret.setAttribute( 'aria-expanded', 'false' );
}
} );
item.classList.toggle( 'ew-menu-open', willOpen );
caret.setAttribute( 'aria-expanded', willOpen ? 'true' : 'false' );
} );
item.appendChild( caret );
item.appendChild( dropdown );
} );
document.addEventListener( 'click', function () {
Array.prototype.forEach.call( topbar.querySelectorAll( '.ew-menu-open' ), function ( item ) {
item.classList.remove( 'ew-menu-open' );
var caret = item.querySelector( '.ew-topbar-caret' );
if ( caret ) {
caret.setAttribute( 'aria-expanded', 'false' );
}
} );
} );
document.addEventListener( 'keydown', function ( event ) {
if ( event.key === 'Escape' ) {
Array.prototype.forEach.call( topbar.querySelectorAll( '.ew-menu-open' ), function ( item ) {
item.classList.remove( 'ew-menu-open' );
var caret = item.querySelector( '.ew-topbar-caret' );
if ( caret ) {
caret.setAttribute( 'aria-expanded', 'false' );
}
} );
}
} );
}
function makeHomepageCardsClickable() {
Array.prototype.forEach.call( document.querySelectorAll( '.ew-card' ), function ( card ) {
var link = card.querySelector( 'a[href]' );
if ( !link ) {
return;
}
card.setAttribute( 'tabindex', '0' );
card.setAttribute( 'role', 'link' );
card.addEventListener( 'click', function ( event ) {
if ( !event.target.closest( 'a' ) ) {
window.location.href = link.href;
}
} );
card.addEventListener( 'keydown', function ( event ) {
if ( event.key === 'Enter' || event.key === ' ' ) {
event.preventDefault();
window.location.href = link.href;
}
} );
} );
}
function loadRecentChanges() {
var loading = document.querySelector( '.ew-recent-loading' );
if ( !loading ) {
return;
}
var api = new mw.Api();
api.get( {
action: 'query',
list: 'recentchanges',
rcnamespace: 0,
rcshow: '!bot',
rcprop: 'title|timestamp|user',
rctype: 'edit|new',
rclimit: 5,
formatversion: 2
} ).then( function ( data ) {
var changes = data && data.query && data.query.recentchanges ? data.query.recentchanges : [];
loading.textContent = '';
if ( !changes.length ) {
loading.textContent = 'No recent article changes.';
return;
}
changes.forEach( function ( change ) {
var row = document.createElement( 'div' );
row.className = 'ew-recent-row';
var icon = document.createElement( 'span' );
icon.className = 'ew-recent-icon';
icon.textContent = change.title.slice( 0, 2 ).toUpperCase();
var copy = document.createElement( 'span' );
var link = document.createElement( 'a' );
link.href = mw.util.getUrl( change.title );
link.textContent = change.title;
var detail = document.createElement( 'small' );
var date = new Date( change.timestamp );
detail.textContent = date.toLocaleDateString() + ( change.user ? ' - ' + change.user : '' );
copy.appendChild( link );
copy.appendChild( detail );
row.appendChild( icon );
row.appendChild( copy );
loading.appendChild( row );
} );
} ).catch( function () {
loading.textContent = 'Recent changes could not be loaded.';
} );
}
mw.loader.using( [ 'mediawiki.api', 'mediawiki.util' ] ).then( function () {
onReady( function () {
installSidebarToggle();
installTopbarDropdowns();
makeHomepageCardsClickable();
loadRecentChanges();
} );
} );
}() );