User:Sophivorus/comparator.js
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
const Comparator = {
init( $content ) {
$content.find( '.template-compare' ).each( Comparator.makeTable );
},
async makeTable() {
// Load WikitextParser.js
// See https://www.mediawiki.org/wiki/WikitextParser.js
await mw.loader.getScript( '//www.mediawiki.org/w/index.php?title=MediaWiki:Gadget-Global-WikitextParser.js&action=raw&ctype=text/javascript' );
// Make the Vue app
const require = await mw.loader.using( '@wikimedia/codex' );
const Vue = require( 'vue' );
const Codex = require( '@wikimedia/codex' );
const app = Vue.createMwApp( Comparator.rootComponent, this.dataset );
app.component( 'cdx-table', Codex.CdxTable );
app.mount( this );
},
rootComponent: {
props: [ 'seed' ],
template: `<cdx-table
:caption="caption"
:columns="columns"
:data="data"
v-model:sort="sort"
@update:sort="onSort"
>
<template #item-title="{ item }">
<span v-html="item"></span>
</template>
</cdx-table>`,
data() {
return {
caption: this.seed,
columns: [
{ id: 'title', label: 'Title', allowSort: true },
{ id: 'language', label: 'Language', allowSort: true },
{ id: 'lead', label: 'Lead', allowSort: true },
{ id: 'image', label: 'Image', allowSort: true },
{ id: 'length', label: 'Length', allowSort: true },
{ id: 'sections', label: 'Sections', allowSort: true },
{ id: 'images', label: 'Images', allowSort: true },
{ id: 'links', label: 'Links', allowSort: true },
{ id: 'editors', label: 'Editors', allowSort: true },
{ id: 'references', label: 'References', allowSort: true },
],
data: [],
sort: {},
};
},
async mounted() {
const titles = [];
const seed = this.seed;
const seedTitle = new mw.Title( seed );
// Category
if ( seedTitle.getNamespaceId() === 14 ) {
const query = {
action: 'query',
list: 'categorymembers',
cmlimit: 'max',
cmtitle: seedTitle.getPrefixedText(),
formatversion: 2,
};
const result = await new mw.Api().get( query );
for ( const categorymember of result.query.categorymembers ) {
titles.push( categorymember.title );
}
}
for ( const title of titles ) {
const query = {
action: 'query',
titles: title,
prop: 'info|images|links|contributors|revisions|pageimages',
imlimit: 'max',
pllimit: 'max',
pclimit: 'max',
piprop: 'name',
rvprop: 'content',
rvslots: 'main',
formatversion: 2,
};
const result = await new mw.Api().get( query );
const page = result.query.pages[0];
const wikitext = page.revisions[0].slots.main.content;
// Determine if there's lead text
let leadWikitext = WikitextParser.getLeadSection( wikitext );
const leadTemplates = WikitextParser.getTemplates( leadWikitext );
for ( const leadTemplate of leadTemplates ) {
leadWikitext = leadWikitext.replace( leadTemplate, '' );
}
const leadFiles = WikitextParser.getFiles( leadWikitext );
for ( const leadFile of leadFiles ) {
leadWikitext = leadWikitext.replace( leadFile, '' );
}
// Determine the number of sections
const sectionTitles = WikitextParser.getSectionTitles( wikitext );
// Determine the number of references
const references = WikitextParser.getReferences( wikitext );
// Build the title link
const titleObject = new mw.Title( page.title );
const titleUrl = titleObject.getUrl();
const titleLink = '<a target="_blank" href="' + titleUrl + '">' + page.title + '</a>';
const data = {
title: titleLink,
language: page.pagelanguage,
lead: leadWikitext ? 'Yes' : 'No',
image: page.pageimage ? 'Yes' : 'No',
length: page.length,
sections: sectionTitles.length,
images: page.images && page.images.length || 0,
links: page.links && page.links.length || 0,
editors: page.contributors && page.contributors.length || 0,
references: references.length,
};
this.data.push( data );
}
},
methods: {
onSort( newSort ) {
this.sort = newSort;
const sortKey = Object.keys( newSort )[0];
const sortOrder = newSort[ sortKey ];
function sortNumerically( data, columnId, sortDir ) {
return data.sort( ( a, b ) => {
if ( sortDir === 'asc' ) {
return b[ columnId ] - a[ columnId ];
}
return a[ columnId ] - b[ columnId ];
} );
}
function sortAlphabetically( data, columnId, sortDir ) {
return data.sort( ( a, b ) => {
const multiplier = sortDir === 'asc' ? 1 : -1;
return multiplier * ( a[ columnId ].localeCompare( b[ columnId ] ) );
} );
}
// Sort data
switch ( sortKey ) {
case 'title':
case 'language':
case 'lead':
case 'image':
this.data = sortAlphabetically( this.data, sortKey, sortOrder );
break;
case 'length':
case 'sections':
case 'images':
case 'links':
case 'editors':
case 'references':
this.data = sortNumerically( this.data, sortKey, sortOrder );
break;
}
}
}
}
};
mw.hook( 'wikipage.content' ).add( Comparator.init );