MediaWiki:Common.js: Difference between revisions
Jump to navigation
Jump to search
mNo edit summary |
mNo edit summary |
||
| Line 3: | Line 3: | ||
'use strict'; | 'use strict'; | ||
var | var DEFAULTS = { | ||
minBytes: 3000, | minBytes: 3000, | ||
dailyStable: true, | |||
blurbChars: | blurbChars: 200 | ||
}; | }; | ||
function init() { | function init() { | ||
var | var panels = document.querySelectorAll( '.lhc-article' ); | ||
if ( ! | if ( !panels.length ) { | ||
return; | return; | ||
} | } | ||
var api = new mw.Api(); | |||
Array.prototype.forEach.call( panels, function ( panel ) { | |||
start( api, panel ); | |||
} ); | |||
} | |||
function start( api, panel ) { | |||
var page = resolvePage( panel ); | |||
if ( page ) { | |||
return loadArticle( api, panel, page ).catch( function () { | |||
} ); | |||
} | |||
var category = panel.getAttribute( 'data-category' ); | |||
if ( !category ) { | |||
return; | |||
} | |||
return pickRandom( api, panel, category ).catch( function () {} ); | |||
} | |||
function resolvePage( panel ) { | |||
var explicit = panel.getAttribute( 'data-page' ); | |||
if ( explicit ) { | |||
return explicit; | |||
} | |||
var link = panel.querySelector( 'a[title]' ); | |||
if ( !link ) { | |||
return null; | |||
} | |||
var title = link.getAttribute( 'title' ); | |||
if ( /\(page does not exist\)$/.test( title ) ) { | |||
return null; | |||
} | |||
return title; | |||
} | |||
var | function pickRandom( api, panel, category ) { | ||
var minBytes = parseInt( panel.getAttribute( 'data-min-bytes' ), 10 ); | |||
if ( isNaN( minBytes ) ) { | |||
minBytes = DEFAULTS.minBytes; | |||
} | |||
api.get( { | return api.get( { | ||
action: 'query', | action: 'query', | ||
generator: 'categorymembers', | generator: 'categorymembers', | ||
gcmtitle: 'Category:' + | gcmtitle: 'Category:' + category, | ||
gcmnamespace: 0, | gcmnamespace: 0, | ||
gcmtype: 'page', | gcmtype: 'page', | ||
| Line 31: | Line 70: | ||
var candidates = pages.filter( function ( p ) { | var candidates = pages.filter( function ( p ) { | ||
return p.length >= | return p.length >= minBytes; | ||
} ).sort( function ( a, b ) { | } ).sort( function ( a, b ) { | ||
// Stable order matters for the daily-seed pick. | // Stable order matters for the daily-seed pick. | ||
| Line 38: | Line 77: | ||
if ( !candidates.length ) { | if ( !candidates.length ) { | ||
mw.log.warn( '[lhc-article] no candidates in ' + category ); | |||
return; | |||
} | } | ||
return loadArticle( | |||
api, panel, candidates[ pickIndex( candidates.length ) ].title | |||
); | |||
} ); | } ); | ||
} | } | ||
function pickIndex( n ) { | function pickIndex( n ) { | ||
if ( ! | if ( !DEFAULTS.dailyStable ) { | ||
return Math.floor( Math.random() * n ); | return Math.floor( Math.random() * n ); | ||
} | } | ||
var d = new Date(); | var d = new Date(); | ||
var key = | var key = d.getUTCFullYear() + '-' + | ||
( d.getUTCMonth() + 1 ) + '-' + d.getUTCDate(); | |||
var h = 2166136261; | var h = 2166136261; | ||
for ( var i = 0; i < key.length; i++ ) { | for ( var i = 0; i < key.length; i++ ) { | ||
| Line 61: | Line 101: | ||
} | } | ||
function loadArticle( api, | function loadArticle( api, panel, title ) { | ||
return api.get( { | return api.get( { | ||
action: 'parse', | action: 'parse', | ||
| Line 72: | Line 112: | ||
var html = data.parse && data.parse.text; | var html = data.parse && data.parse.text; | ||
if ( !html ) { | if ( !html ) { | ||
return | return; | ||
} | } | ||
var doc = new DOMParser().parseFromString( html, 'text/html' ); | var doc = new DOMParser().parseFromString( html, 'text/html' ); | ||
render( panel, { | |||
render( | // Use the resolved title, so redirects show their target. | ||
title: title, | title: data.parse.title || title, | ||
image: extractImage( doc ), | image: extractImage( doc ), | ||
blurb: extractBlurb( doc ) | blurb: extractBlurb( doc ) | ||
| Line 97: | Line 136: | ||
return null; | return null; | ||
} | } | ||
if ( src.indexOf( '//' ) === 0 ) { | if ( src.indexOf( '//' ) === 0 ) { | ||
return location.protocol + src; | return location.protocol + src; | ||
| Line 106: | Line 144: | ||
return src; | return src; | ||
} | } | ||
function extractBlurb( doc ) { | function extractBlurb( doc ) { | ||
var junk = doc.querySelectorAll( | var junk = doc.querySelectorAll( | ||
| Line 120: | Line 158: | ||
var text = paras[ i ].textContent.replace( /\s+/g, ' ' ).trim(); | var text = paras[ i ].textContent.replace( /\s+/g, ' ' ).trim(); | ||
if ( text.length > 40 ) { | if ( text.length > 40 ) { | ||
return truncate( text, | return truncate( text, DEFAULTS.blurbChars ); | ||
} | } | ||
} | } | ||
| Line 135: | Line 173: | ||
} | } | ||
function render( | function render( panel, article ) { | ||
var href = mw.util.getUrl( article.title ); | var href = mw.util.getUrl( article.title ); | ||
| Line 147: | Line 185: | ||
img.src = article.image; | img.src = article.image; | ||
img.alt = article.title; | img.alt = article.title; | ||
link.appendChild( img ); | link.appendChild( img ); | ||
wrap.appendChild( link ); | wrap.appendChild( link ); | ||
} | } | ||
var heading = document.createElement( 'div' ); | var heading = document.createElement( 'div' ); | ||
| Line 161: | Line 195: | ||
titleLink.textContent = article.title; | titleLink.textContent = article.title; | ||
heading.appendChild( titleLink ); | heading.appendChild( titleLink ); | ||
wrap.appendChild( heading ); | |||
if ( article.blurb ) { | if ( article.blurb ) { | ||
| Line 167: | Line 201: | ||
p.className = 'lhc-ra-blurb'; | p.className = 'lhc-ra-blurb'; | ||
p.textContent = article.blurb; | p.textContent = article.blurb; | ||
wrap.appendChild( p ); | |||
} | } | ||
| Line 174: | Line 208: | ||
more.className = 'lhc-ra-more'; | more.className = 'lhc-ra-more'; | ||
more.textContent = 'Read the full article →'; | more.textContent = 'Read the full article →'; | ||
wrap.appendChild( more ); | |||
panel.textContent = ''; | |||
panel.appendChild( wrap ); | |||
} | } | ||
Revision as of 04:33, 14 August 2026
/* Any JavaScript here will be loaded for all users on every page load. */
( function () {
'use strict';
var DEFAULTS = {
minBytes: 3000,
dailyStable: true,
blurbChars: 200
};
function init() {
var panels = document.querySelectorAll( '.lhc-article' );
if ( !panels.length ) {
return;
}
var api = new mw.Api();
Array.prototype.forEach.call( panels, function ( panel ) {
start( api, panel );
} );
}
function start( api, panel ) {
var page = resolvePage( panel );
if ( page ) {
return loadArticle( api, panel, page ).catch( function () {
} );
}
var category = panel.getAttribute( 'data-category' );
if ( !category ) {
return;
}
return pickRandom( api, panel, category ).catch( function () {} );
}
function resolvePage( panel ) {
var explicit = panel.getAttribute( 'data-page' );
if ( explicit ) {
return explicit;
}
var link = panel.querySelector( 'a[title]' );
if ( !link ) {
return null;
}
var title = link.getAttribute( 'title' );
if ( /\(page does not exist\)$/.test( title ) ) {
return null;
}
return title;
}
function pickRandom( api, panel, category ) {
var minBytes = parseInt( panel.getAttribute( 'data-min-bytes' ), 10 );
if ( isNaN( minBytes ) ) {
minBytes = DEFAULTS.minBytes;
}
return api.get( {
action: 'query',
generator: 'categorymembers',
gcmtitle: 'Category:' + category,
gcmnamespace: 0,
gcmtype: 'page',
gcmlimit: 'max',
prop: 'info',
formatversion: 2
} ).then( function ( data ) {
var pages = ( data.query && data.query.pages ) || [];
var candidates = pages.filter( function ( p ) {
return p.length >= minBytes;
} ).sort( function ( a, b ) {
// Stable order matters for the daily-seed pick.
return a.title.localeCompare( b.title );
} );
if ( !candidates.length ) {
mw.log.warn( '[lhc-article] no candidates in ' + category );
return;
}
return loadArticle(
api, panel, candidates[ pickIndex( candidates.length ) ].title
);
} );
}
function pickIndex( n ) {
if ( !DEFAULTS.dailyStable ) {
return Math.floor( Math.random() * n );
}
var d = new Date();
var key = d.getUTCFullYear() + '-' +
( d.getUTCMonth() + 1 ) + '-' + d.getUTCDate();
var h = 2166136261;
for ( var i = 0; i < key.length; i++ ) {
h = ( h ^ key.charCodeAt( i ) ) * 16777619 >>> 0;
}
return h % n;
}
function loadArticle( api, panel, title ) {
return api.get( {
action: 'parse',
page: title,
prop: 'text',
section: 0,
redirects: 1,
formatversion: 2
} ).then( function ( data ) {
var html = data.parse && data.parse.text;
if ( !html ) {
return;
}
var doc = new DOMParser().parseFromString( html, 'text/html' );
render( panel, {
// Use the resolved title, so redirects show their target.
title: data.parse.title || title,
image: extractImage( doc ),
blurb: extractBlurb( doc )
} );
} );
}
function extractImage( doc ) {
var img = doc.querySelector(
'.infobox img, .infobox-image img, table.infobox img'
) || doc.querySelector( 'img' );
if ( !img ) {
return null;
}
var src = img.getAttribute( 'src' );
if ( !src ) {
return null;
}
if ( src.indexOf( '//' ) === 0 ) {
return location.protocol + src;
}
if ( src.indexOf( '/' ) === 0 ) {
return location.origin + src;
}
return src;
}
function extractBlurb( doc ) {
var junk = doc.querySelectorAll(
'table, .infobox, .navbox, .hatnote, .thumb, ' +
'sup.reference, .mw-editsection, .noexcerpt, style'
);
Array.prototype.forEach.call( junk, function ( el ) {
el.parentNode.removeChild( el );
} );
var paras = doc.querySelectorAll( 'p' );
for ( var i = 0; i < paras.length; i++ ) {
var text = paras[ i ].textContent.replace( /\s+/g, ' ' ).trim();
if ( text.length > 40 ) {
return truncate( text, DEFAULTS.blurbChars );
}
}
return null;
}
function truncate( text, max ) {
if ( text.length <= max ) {
return text;
}
var cut = text.slice( 0, max );
var space = cut.lastIndexOf( ' ' );
return ( space > 0 ? cut.slice( 0, space ) : cut ) + '…';
}
function render( panel, article ) {
var href = mw.util.getUrl( article.title );
var wrap = document.createElement( 'div' );
wrap.className = 'lhc-ra';
if ( article.image ) {
var link = document.createElement( 'a' );
link.href = href;
var img = document.createElement( 'img' );
img.src = article.image;
img.alt = article.title;
link.appendChild( img );
wrap.appendChild( link );
}
var heading = document.createElement( 'div' );
heading.className = 'lhc-ra-title';
var titleLink = document.createElement( 'a' );
titleLink.href = href;
titleLink.textContent = article.title;
heading.appendChild( titleLink );
wrap.appendChild( heading );
if ( article.blurb ) {
var p = document.createElement( 'p' );
p.className = 'lhc-ra-blurb';
p.textContent = article.blurb;
wrap.appendChild( p );
}
var more = document.createElement( 'a' );
more.href = href;
more.className = 'lhc-ra-more';
more.textContent = 'Read the full article →';
wrap.appendChild( more );
panel.textContent = '';
panel.appendChild( wrap );
}
mw.loader.using( [ 'mediawiki.api', 'mediawiki.util' ] ).then( function () {
if ( document.readyState !== 'loading' ) {
init();
} else {
document.addEventListener( 'DOMContentLoaded', init );
}
} );
}() );