Difference between revisions of "MediaWiki:Gadget-minipedia.js"
Jump to navigation
Jump to search
m (now the $.when( $.ready ) is not useful) |
(introduce stats box) |
||
| Line 8: | Line 8: | ||
* @revision 2020-06-27 |
* @revision 2020-06-27 |
||
*/ |
*/ |
||
| − | + | ( function ( $, mw ) { |
|
/* |
/* |
||
| Line 37: | Line 37: | ||
createMinipediaPageTitle: "Accesso Minipedia", |
createMinipediaPageTitle: "Accesso Minipedia", |
||
createMinipediaPageBody: "Sii il primo a creare una versione più ridotta e più accessibile di questa voce, in Minipedia!", |
createMinipediaPageBody: "Sii il primo a creare una versione più ridotta e più accessibile di questa voce, in Minipedia!", |
||
| + | statsTitle: "Mini Report", |
||
| + | statsWords: "Parole", |
||
| + | statsLines: "Paragrafi", |
||
| + | statsComplexWords: "Parole complesse", |
||
}; |
}; |
||
| Line 51: | Line 55: | ||
// default edit intro page title |
// default edit intro page title |
||
mp.editIntro = mp.editIntro || 'Progetto:Minipedia/Creazione voce'; |
mp.editIntro = mp.editIntro || 'Progetto:Minipedia/Creazione voce'; |
||
| + | |||
| + | // how much characters should have a word to be considered too much lon |
||
| + | // this somehow help people with dyslexia |
||
| + | mp.longWordLen = 13; |
||
// localization stuff |
// localization stuff |
||
| Line 86: | Line 94: | ||
// no page no party |
// no page no party |
||
return false; |
return false; |
||
| + | }; |
||
| + | |||
| + | /** |
||
| + | * Get a fresh MediaWiki API object |
||
| + | * |
||
| + | * @return mw.Api |
||
| + | */ |
||
| + | function mwApi() { |
||
| + | return mw.loader.using( 'mediawiki.api' ).then( function() { |
||
| + | return new mw.Api(); |
||
| + | } ); |
||
}; |
}; |
||
| Line 96: | Line 115: | ||
function pageExists( title ) { |
function pageExists( title ) { |
||
| − | // |
+ | // prepare the API request |
| + | var request = { |
||
| − | // TODO: check if it's called everytime and eventually put dependency in ResourceLoader |
||
| + | action: 'query', |
||
| − | // this returns the Promise created downstream (false or existing page) |
||
| + | prop: 'info', |
||
| − | return mw.loader.using( 'mediawiki.api' ).then( function() { |
||
| + | titles: title, |
||
| + | }; |
||
| − | + | // eventually load API stuff |
|
| + | return mwApi().then( function( api ) { |
||
| − | var request = { |
||
| − | action: 'query', |
||
| − | prop: 'info', |
||
| − | titles: title |
||
| − | }; |
||
| − | // make the API request |
+ | // make the API request |
| + | return api.get( request ).then( function ( response ) { |
||
| − | // resolve the parent Promise with another Promise giving the existing page or false |
||
| − | return ( new mw.Api() ).get( request ).then( function ( response ) { |
||
// check if it exists |
// check if it exists |
||
| Line 120: | Line 136: | ||
return false; |
return false; |
||
} ); |
} ); |
||
| + | } ); |
||
| + | }; |
||
| + | |||
| + | /** |
||
| + | * Query the current page plain text |
||
| + | * |
||
| + | * @return Promise |
||
| + | */ |
||
| + | function queryPlainText() { |
||
| + | |||
| + | // complete page title with namespace |
||
| + | var pageName = mw.config.get( 'wgPageName' ); |
||
| + | |||
| + | // prepare the API request |
||
| + | // See https://phabricator.wikimedia.org/T259332 |
||
| + | var request = { |
||
| + | action: 'query', |
||
| + | prop: 'extracts', |
||
| + | titles: pageName, |
||
| + | explaintext: 1, |
||
| + | exlimit: 1, |
||
| + | exsectionformat: 'plain', |
||
| + | }; |
||
| + | |||
| + | // this will return a Promise resolving the page plain text, returned upstream |
||
| + | return mwApi().then( function( api ) { |
||
| + | |||
| + | // make the API request and return a Promise |
||
| + | return api.get( request ).then( function( response ) { |
||
| + | // resolve the Promise with the page content |
||
| + | var page = justFirstQueryPage( response ); |
||
| + | if( page && page.pageid && page.pageid > 0 && page.extract ) { |
||
| + | return page.extract; |
||
| + | } |
||
| + | |||
| + | // no content |
||
| + | return false; |
||
| + | |||
| + | } ); |
||
} ); |
} ); |
||
}; |
}; |
||
| Line 214: | Line 269: | ||
// check if you accepted the page creation |
// check if you accepted the page creation |
||
windowInstance.closed.then( function ( data ) { |
windowInstance.closed.then( function ( data ) { |
||
| + | |||
| + | // user is confirming action |
||
if( data.action === 'accept' ) { |
if( data.action === 'accept' ) { |
||
| Line 235: | Line 292: | ||
}; |
}; |
||
// end prepareNormalWiki() |
// end prepareNormalWiki() |
||
| + | |||
| + | /** |
||
| + | * Calculate some stats over a text |
||
| + | */ |
||
| + | function textStats( text ) { |
||
| + | |||
| + | var stats = {}; |
||
| + | |||
| + | text = text.trim(); |
||
| + | |||
| + | // count long words |
||
| + | var totalLongWords = 0; |
||
| + | var word, words = text.split( /\s+/ ); |
||
| + | for( var i = 0; i < words.length; i++ ) { |
||
| + | word = words[i]; |
||
| + | if( word.length > mp.longWordLen ) { |
||
| + | totalLongWords++; |
||
| + | } |
||
| + | } |
||
| + | |||
| + | // how much lines? |
||
| + | stats.totalLines = text.split( "\n+" ).length; |
||
| + | |||
| + | // how much words? |
||
| + | stats.totalWords = words.length; |
||
| + | |||
| + | // how much of these words are so much long? |
||
| + | // See 'longWordLen' |
||
| + | stats.totalLongWords = totalLongWords; |
||
| + | |||
| + | return stats; |
||
| + | }; |
||
| + | |||
| + | /** |
||
| + | * Query content stats of the current page |
||
| + | * |
||
| + | * @return Promise |
||
| + | */ |
||
| + | function queryContentStats() { |
||
| + | return queryPlainText().then( textStats ); |
||
| + | }; |
||
| + | |||
| + | /** |
||
| + | * Prepare the Minipedia stats box |
||
| + | */ |
||
| + | function prepareMinipediaStatsBox() { |
||
| + | |||
| + | // body container |
||
| + | var $contentText = $( '#mw-content-text' ); |
||
| + | |||
| + | // prepare the DOM tree |
||
| + | var $container = $( '<div>' ); |
||
| + | var $table = $( '<table>' ); |
||
| + | var $thead = $( '<tbody>' ); |
||
| + | |||
| + | // prepare the stats container |
||
| + | $container.addClass( 'minipedia-stats' ); |
||
| + | |||
| + | // put a title |
||
| + | $container.append( $( '<h2>' ).text( mp.L10N.statsTitle ) ); |
||
| + | |||
| + | // put the table |
||
| + | $container.append( $table ); |
||
| + | |||
| + | // prepare the table |
||
| + | $table.addClass( 'wikitable' ) |
||
| + | .append( $thead ); |
||
| + | |||
| + | /** |
||
| + | * Append a row (with a label and a value) into a table |
||
| + | * |
||
| + | * @param {Object} jQuery table |
||
| + | * @param {String} className |
||
| + | * @param {String} label |
||
| + | * @param {String} value |
||
| + | */ |
||
| + | function appendTableStatsRow( $table, className, label, value ) { |
||
| + | var $tr = $( '<tr>' ); |
||
| + | $tr.addClass( 'minipedia-stats-row-' + className ); |
||
| + | $tr.append( $( '<td>' ).text( label ) ); |
||
| + | $tr.append( $( '<td>' ).text( value ) ); |
||
| + | $table.append( $tr ); |
||
| + | }; |
||
| + | |||
| + | // query the page plain text |
||
| + | queryContentStats().then( function( stats ) { |
||
| + | |||
| + | // show the number of words, lines and complex words (actually just long words) |
||
| + | appendTableStatsRow( $table, 'long-words', mp.L10N.statsComplexWords, stats.totalLongWords ); |
||
| + | appendTableStatsRow( $table, 'words', mp.L10N.statsWords, stats.totalWords ); |
||
| + | appendTableStatsRow( $table, 'lines', mp.L10N.statsLines, stats.totalLines ); |
||
| + | } ); |
||
| + | |||
| + | // show the stats container at the bottom of the page |
||
| + | $contentText.append( $container ); |
||
| + | }; |
||
/** |
/** |
||
| Line 240: | Line 393: | ||
*/ |
*/ |
||
function prepareMinipedia() { |
function prepareMinipedia() { |
||
| + | |||
| + | // action of the page (edit, view etc.) |
||
| + | var action = mw.config.get( 'wgAction' ); |
||
// normal page title and mini version |
// normal page title and mini version |
||
| Line 261: | Line 417: | ||
L10N.openNormalpedia |
L10N.openNormalpedia |
||
); |
); |
||
| + | |||
| + | // check if we are in view mode |
||
| + | if( action === 'view' ) { |
||
| + | |||
| + | // in view mode we can fetch the stats |
||
| + | prepareMinipediaStatsBox(); |
||
| + | } |
||
}; |
}; |
||
// end prepareMinipedia() |
// end prepareMinipedia() |
||
| Line 273: | Line 436: | ||
// end namespace zero check |
// end namespace zero check |
||
| − | } ); |
+ | } )( $, mw ); |
Revision as of 17:21, 31 July 2020
/**
* Make Minipedia magics
*
* Dependencies: mediawiki.util
*
* See https://phabricator.wikimedia.org/tag/minipedia/
*
* @revision 2020-06-27
*/
( function ( $, mw ) {
/*
* CONFIGURATION/LOCALIZATION INSTRUCTIONS
*
* Declare somewhere something like this:
*
* // assure that you do not overwrite other-people customizations
* window.MiniPedia = window.MiniPedia || {};
* window.MiniPedia.L10N = window.MiniPedia.L10N || {};
*
* // then customize something
* window.MiniPedia.editIntro = 'Project:How to create';
* window.MiniPedia.L10N.minipedia = 'Otherpedia';
*
* For all the strings available in the 'MiniPedia.L10N' object
* see the L10N_DEFAULTS variable below.
*/
// load localization defaults
var L10N_DEFAULTS = {
minipedia: "Minipedia",
minipediaShort: "Mini",
normalpedia: "Wikipedia Test",
normalpediaShort: "WikipediaTest",
openMinipedia: "Apri Minipedia",
openNormalpedia: "Apri Wikipedia Test",
createMinipediaPageTitle: "Accesso Minipedia",
createMinipediaPageBody: "Sii il primo a creare una versione più ridotta e più accessibile di questa voce, in Minipedia!",
statsTitle: "Mini Report",
statsWords: "Parole",
statsLines: "Paragrafi",
statsComplexWords: "Parole complesse",
};
// global configuration file
window.MiniPedia = window.MiniPedia || {};
// shortcut for the global configuration file (mp = mini-pedia)
var mp = window.MiniPedia;
// default namespace informations
mp.namespace = mp.namespace || 'Mini';
mp.namespaceNum = mp.namespaceNum || 3002;
// default edit intro page title
mp.editIntro = mp.editIntro || 'Progetto:Minipedia/Creazione voce';
// how much characters should have a word to be considered too much lon
// this somehow help people with dyslexia
mp.longWordLen = 13;
// localization stuff
mp.L10N = mp.L10N || {};
// shortcut
var L10N = mp.L10N;
// load the defaults
for( var key in L10N_DEFAULTS ) {
if( !L10N[ key ] ) {
L10N[ key ] = L10N_DEFAULTS[ key ];
}
}
/**
* Lazy shortcut to obtain just the first API result
*
* @param {Object} response API Response
* @return {Object} page object
*/
function justFirstQueryPage( response ) {
// no response no party
if( !response.query || !response.query.pages ) {
throw 'no valid API response';
}
// the list should contain just one page
var pages = response.query.pages;
for( var id in pages ) {
return pages[ id ];
}
// no page no party
return false;
};
/**
* Get a fresh MediaWiki API object
*
* @return mw.Api
*/
function mwApi() {
return mw.loader.using( 'mediawiki.api' ).then( function() {
return new mw.Api();
} );
};
/**
* Check if a page title already exists
*
* @param title Page title
* @return Promise
*/
function pageExists( title ) {
// prepare the API request
var request = {
action: 'query',
prop: 'info',
titles: title,
};
// eventually load API stuff
return mwApi().then( function( api ) {
// make the API request
return api.get( request ).then( function ( response ) {
// check if it exists
var page = justFirstQueryPage( response );
if( page && page.pageid && page.pageid > 0 ) {
return page;
}
return false;
} );
} );
};
/**
* Query the current page plain text
*
* @return Promise
*/
function queryPlainText() {
// complete page title with namespace
var pageName = mw.config.get( 'wgPageName' );
// prepare the API request
// See https://phabricator.wikimedia.org/T259332
var request = {
action: 'query',
prop: 'extracts',
titles: pageName,
explaintext: 1,
exlimit: 1,
exsectionformat: 'plain',
};
// this will return a Promise resolving the page plain text, returned upstream
return mwApi().then( function( api ) {
// make the API request and return a Promise
return api.get( request ).then( function( response ) {
// resolve the Promise with the page content
var page = justFirstQueryPage( response );
if( page && page.pageid && page.pageid > 0 && page.extract ) {
return page.extract;
}
// no content
return false;
} );
} );
};
/**
* Prepare the wiki
*/
function prepareNormalpedia() {
// normal page title and mini version
var pageName = mw.config.get( 'wgPageName' );
// prepare the Minipedia title object
var miniTitleObject = new mw.Title( pageName, mp.namespaceNum );
// minipedia page title with prefix
var miniPageName = miniTitleObject.getPrefixedText();
// minipedia page URL
var miniPageUrl = miniTitleObject.getUrl();
/**
* Go to the Minipedia page in edit mode
*
* The page in the main namespace will be preloaded.
*/
function goToMinipediaEditPage() {
/**
* Build the query string to edit a page
*
* TODO: eventually add VisualEditor support
*/
var editPageQueryString = {
action: 'edit',
title: miniPageName,
preload: pageName,
editintro: mp.editIntro,
};
// '/index.php'
var wgScript = mw.config.get( 'wgScript' );
// go to the edit page URL
window.location = wgScript + '?' + $.param( editPageQueryString );
};
// add a "Minipedia"
var miniVersionPortletLink = mw.util.addPortletLink(
'p-namespaces',
miniPageUrl,
L10N.minipediaShort,
'ca-minipedia',
L10N.openMinipedia,
'n'
);
// on the mini toolback click, check if a mini version exists
$( miniVersionPortletLink ).click( function( e ) {
// wait for some information
$.when(
// check if the page really exists
pageExists( miniPageName ),
// allow to open OO UI windows
mw.loader.using( 'oojs-ui-windows' )
).done( function( miniPageExists, loader ) {
// check if the page already exist
if( miniPageExists ) {
// just redirect to the Minipedia version
window.location = miniPageUrl;
} else {
// ask if you want to create the page
// create message dialog window
var messageDialog = new OO.ui.MessageDialog();
var windowManager = new OO.ui.WindowManager();
$( 'body' ).append( windowManager.$element );
windowManager.addWindows( [ messageDialog ] );
// configure and open dialog
var windowInstance = windowManager.openWindow( messageDialog, {
title: L10N.createMinipediaPageTitle,
message: L10N.createMinipediaPageBody,
} );
// check if you accepted the page creation
windowInstance.closed.then( function ( data ) {
// user is confirming action
if( data.action === 'accept' ) {
// go go go!
goToMinipediaEditPage();
}
} );
}
// end if page exists
} );
// end $.when()
// avoid scrolling to the top
e.preventDefault();
} );
// end $( miniVersionPortletLink ).click
};
// end prepareNormalWiki()
/**
* Calculate some stats over a text
*/
function textStats( text ) {
var stats = {};
text = text.trim();
// count long words
var totalLongWords = 0;
var word, words = text.split( /\s+/ );
for( var i = 0; i < words.length; i++ ) {
word = words[i];
if( word.length > mp.longWordLen ) {
totalLongWords++;
}
}
// how much lines?
stats.totalLines = text.split( "\n+" ).length;
// how much words?
stats.totalWords = words.length;
// how much of these words are so much long?
// See 'longWordLen'
stats.totalLongWords = totalLongWords;
return stats;
};
/**
* Query content stats of the current page
*
* @return Promise
*/
function queryContentStats() {
return queryPlainText().then( textStats );
};
/**
* Prepare the Minipedia stats box
*/
function prepareMinipediaStatsBox() {
// body container
var $contentText = $( '#mw-content-text' );
// prepare the DOM tree
var $container = $( '<div>' );
var $table = $( '<table>' );
var $thead = $( '<tbody>' );
// prepare the stats container
$container.addClass( 'minipedia-stats' );
// put a title
$container.append( $( '<h2>' ).text( mp.L10N.statsTitle ) );
// put the table
$container.append( $table );
// prepare the table
$table.addClass( 'wikitable' )
.append( $thead );
/**
* Append a row (with a label and a value) into a table
*
* @param {Object} jQuery table
* @param {String} className
* @param {String} label
* @param {String} value
*/
function appendTableStatsRow( $table, className, label, value ) {
var $tr = $( '<tr>' );
$tr.addClass( 'minipedia-stats-row-' + className );
$tr.append( $( '<td>' ).text( label ) );
$tr.append( $( '<td>' ).text( value ) );
$table.append( $tr );
};
// query the page plain text
queryContentStats().then( function( stats ) {
// show the number of words, lines and complex words (actually just long words)
appendTableStatsRow( $table, 'long-words', mp.L10N.statsComplexWords, stats.totalLongWords );
appendTableStatsRow( $table, 'words', mp.L10N.statsWords, stats.totalWords );
appendTableStatsRow( $table, 'lines', mp.L10N.statsLines, stats.totalLines );
} );
// show the stats container at the bottom of the page
$contentText.append( $container );
};
/**
* Prepare the Minipedia namespace
*/
function prepareMinipedia() {
// action of the page (edit, view etc.)
var action = mw.config.get( 'wgAction' );
// normal page title and mini version
var pageName = mw.config.get( 'wgTitle' );
// prepare the Normalpedia title object
var normalTitleObject = new mw.Title( pageName );
// minipedia page title with prefix
var normalPageName = normalTitleObject.getPrefixedText();
// minipedia page URL
var normalPageUrl = normalTitleObject.getUrl();
// add a "Minipedia"
var normalVersionPortletLink = mw.util.addPortletLink(
'p-namespaces',
normalPageUrl,
L10N.normalpediaShort,
'ca-normalpedia',
L10N.openNormalpedia
);
// check if we are in view mode
if( action === 'view' ) {
// in view mode we can fetch the stats
prepareMinipediaStatsBox();
}
};
// end prepareMinipedia()
// work only in the main namespace
var ns = mw.config.get( 'wgNamespaceNumber' );
if( ns === 0 ) {
prepareNormalpedia();
} else if( ns == mp.namespaceNum ) {
prepareMinipedia();
}
// end namespace zero check
} )( $, mw );