User:Schnark/mostEdited.js
Appearance
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.
/**
* User:Schnark/mostEdited.js
*
* User script to show the pages which were edited most in the last time
* For a documentation see [[User:Schnark/mostEdited]]
* For the history behind this script see [[User:Schnark/October 2011 Coding Challenge]]
*
* @author Michael Müller ([[User:Schnark]])
* @license GPL [//www.mediawiki.org/w/COPYING] (+ CC-BY-SA as all pages in this wiki)
*
*
* Copyright (C) 2011 Michael Müller
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to
*
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301, USA.
*
* <nowiki>
*/
/*global jQuery: true, mw: true */
( function ( $ ) {
// since there is no good way to get messages in a user script (yet), jsut put them here
/**
* @var {object} fallback language
* Please note the following things:
* 1. en is fallback in any way
* 2. fallback languages will be resolved only one step
* 3. every fallback *must* have an entry in the messages structure
* 4. this sucks
*/
var languageFallback = {
'bar': 'de',
'de-at': 'de',
'de-ch': 'de',
'de-formal': 'de',
'dsb': 'de',
'frr': 'de',
'gsw': 'de',
'hsb': 'de',
'ksh': 'de',
'lb': 'de',
'nds': 'de',
'pdc': 'de',
'pdt': 'de',
'pfl': 'de',
'sli': 'de',
'stq': 'de',
'vmf': 'de'
};
/**
* @var {object} messages for a language
*/
var messages = {
en: {
// from core
'minutes': '{{PLURAL:$1|$1 minute|$1 minutes}}',
'hours': '{{PLURAL:$1|$1 hour|$1 hours}}',
'days': '{{PLURAL:$1|$1 day|$1 days}}',
'allpagessubmit': 'Go',
'namespace': 'Namespace:',
'invert': 'Invert selection',
'tooltip-invert': 'Check this box to hide changes within the selected namespace (and the associated namespace if checked)',
'namespace_association': 'Associated namespace',
'tooltip-namespace_association': 'Check this box to also include the talk or subject namespace associated with the selected namespace',
'blanknamespace': '(Main)',
'namespacesall': 'all',
'rc-change-size': '$1',
'pagetitle': '$1 - {{SITENAME}}',
// own messages
'mostedited-legend': 'Most edited pages options', // legend for options on BlankPage with action=mostedited
'mostedited': 'Most edited pages', // link in sidebar and title of the page
'tooltip-n-mostedited': 'Shows the most edited pages', // tooltip for link in sidebar
'mostedited-submit': 'Show most edited pages', // submit button in RecentChanges
'mostedited-time': 'Time:', // label for time selection
'mostedited-edits': '{{PLURAL:$1|$1 edit|$1 edits}} ($2 minor {{PLURAL:$2|edit|edits}})', // $1 - total number of edits to the page/section, $2 - number of minor edits
'mostedited-users': '{{PLURAL:$1|$1 user|$1 users}} ($2 anonymous {{PLURAL:$2|user|users}})', // $1 - total number of different editors, $2 - number of anonymous editors
'mostedited-size': 'Size change: $1', // $1 - formatted number
'mostedited-no-pages': 'There are no pages with $1 or more edits in the selected period.', // $1 - number of edits a page must have at least to get shown
'mostedited-increasing': 'The number of edits seems to be increasing.',
'mostedited-unchanging': 'The number of edits seems not to change.',
'mostedited-decreasing': 'The number of edits seems to be decreasing.',
'mostedited-changed-period': '(changed to: $1)',
'mostedited-changed-period-tooltip': 'The period had to be shortened because there are too many edits.'
},
de: {
'minutes': '{{PLURAL:$1|$1 Minute|$1 Minuten}}',
'hours': '{{PLURAL:$1|$1 Stunde|$1 Stunden}}',
'days': '{{PLURAL:$1|$1 Tag|$1 Tage}}',
'allpagessubmit': 'Anwenden',
'namespace': 'Namensraum:',
'invert': 'Auswahl umkehren',
'tooltip-invert': 'Dieses Auswahlfeld anklicken, um Änderungen im gewählten Namensraum und, sofern ausgewählt, dem entsprechenden zugehörigen Namensraum auszublenden',
'namespace_association': 'Zugeordneter Namensraum',
'tooltip-namespace_association': 'Dieses Auswahlfeld anklicken, um den deiner Auswahl zugehörigen Diskussionsnamensraum, oder im umgekehrten Fall, den zugehörigen Namensraum, mit einzubeziehen',
'blanknamespace': '(Seiten)',
'namespacesall': 'alle',
'rc-change-size': '$1 {{PLURAL:$1|Byte|Bytes}}',
'pagetitle': '$1 – {{SITENAME}}',
'mostedited-legend': 'Anzeigeptionen',
'mostedited': 'Meiste Änderungen',
'tooltip-n-mostedited': 'Zeigt die Seiten mit den meisten Änderungen an',
'mostedited-submit': 'Zeige Seiten mit meisten Änderungen',
'mostedited-time': 'Zeit:',
'mostedited-edits': '{{PLURAL:$1|$1 Bearbeitung|$1 Bearbeitungen}} ($2 kleinere {{PLURAL:$2|Bearbeitung|Bearbeitungen}})',
'mostedited-users': '$1 Benutzer ({{PLURAL:$2|$2 anonymer|$2 anonyme}})',
'mostedited-size': 'Größenänderung: $1',
'mostedited-no-pages': 'Keine Seite wurde im ausgewählten Zeitraum $1 Mal oder häufiger bearbeitet.',
'mostedited-increasing': 'Die Anzahl der Bearbeitungen scheint zuzunehmen.',
'mostedited-unchanging': 'Die Anzahl der Bearbeitungen scheint gleich zu bleiben.',
'mostedited-decreasing': 'Die Anzahl der Bearbeitungen scheint abzunehmen.',
'mostedited-changed-period': '(geändert in: $1)',
'mostedited-changed-period-tooltip': 'Die Zeit musste gekürzt werden, da zu viele Bearbeitungen stattfanden.'
},
'de-ch': {
'mostedited-size': 'Grössenänderung: $1'
}
};
// set messages for the user's language
// @TODO once there is a better way to do this (new Gadget extension etc.) switch to that way
mw.messages.set( messages.en );
if ( mw.config.get( 'wgUserLanguage' ) in languageFallback ) {
mw.messages.set( messages[languageFallback[mw.config.get( 'wgUserLanguage' )]] );
}
if ( mw.config.get( 'wgUserLanguage' ) in messages ) {
mw.messages.set( messages[mw.config.get( 'wgUserLanguage' )] );
}
// allow users to bind to this event to set messages for their language
$( document ).trigger( 'mostedited-setmessages' );
/**
* @var {object} pagesList contains information for every edited page in the form
* 'Pagename': {
* oldsize: 1234, // size of oldest version
* newsize: 4321, // size of newest version
* edits: 123, // number of edits
* minor: 23, // number of minor edits
* users: ['A', 'B'], // all editors
* anons: 5, // number of anonymous editors
* time: 987654321, // sum of all timestamps (in seconds before now)
* sections: { // data for each section
* 'Section A': {
* edits: 12,
* minor: 2,
* users: ['A'],
* anons: 2,
* time: 87654321
* }
* }
* }
*/
var pagesList = {};
/**
* @var {number} current time, time of first edit (milliseconds since 1970-01-01)
*/
var currTime = 0, firstTime = 0;
// helper and format functions
/**
* gets a message (as an HTML fragment), overridden with a wikitext parser when needed
* @param msgName {string}
* @param parameters {string}
* @return {string}
*/
function msg ( /* msgName, parameters */ ) {
return mw.msg.apply( mw, arguments );
}
/**
* converts a timestamp (YYYY-MM-DDTHH:MM:SSZ) into milliseconds since 1970-01-01
* @param timestamp {string}
* @return {number}
*/
function getTime ( timestamp ) {
return ( new Date( timestamp.slice( 0, 4 ), timestamp.slice( 5, 7 ) - 1, timestamp.slice( 8, 10 ),
timestamp.slice( 11, 13 ), timestamp.slice( 14, 16 ), timestamp.slice( 17, 19 ) ) ).getTime();
}
/**
* encodes a section name to be used as anchor for a link to this section
* @param section {string} title of the section
* @return {string} encoded anchor
*/
function encodeSectionLink ( section ) {
return mw.util.rawurlencode( section.replace( / /g, '_' ) )
.replace( /%3A/g, ':' )
.replace( /%/g, '.' )
.replace( /^([^a-zA-Z])/, 'x$1' );
}
/**
* formats a size change (see ChangesList.php for the original)
* @TODO commafy
* @param diff {number} difference between old and new size
* @return {string} formatted HTML
*/
function showCharacterDifference ( diff ) {
var cssClass, sign = '';
if ( diff < 0 ) {
cssClass = 'mw-plusminus-neg';
} else if ( diff > 0 ) {
sign = '+';
cssClass = 'mw-plusminus-pos';
} else {
cssClass = 'mw-plusminus-null';
}
return mw.html.element( 'span',
{'class': cssClass, dir: 'ltr'},
msg( 'rc-change-size', sign + diff ) );
}
/**
* determins whether the edits are increasing or decreasing
* @param data {object} object with entries edits and time
* @return {string} arrow symbol in a <span> with class and tooltip
*/
function getTrend ( data ) {
var avgTime = data.time / data.edits,
ratio = avgTime / (firstTime - currTime),
cssClass, tooltipMsg, arrow;
if ( ratio < 0.4 ) {
cssClass = 'mw-plusminus-pos';
tooltipMsg = 'mostedited-increasing';
arrow = $( 'body' ).is( '.rtl' ) ? '↖' : '↗';
} else if ( ratio < 0.6 ) {
cssClass = 'mw-plusminus-null';
tooltipMsg = 'mostedited-unchanging';
arrow = $( 'body' ).is( '.rtl' ) ? '←' : '→';
} else {
cssClass = 'mw-plusminus-neg';
tooltipMsg = 'mostedited-decreasing';
arrow = $( 'body' ).is( '.rtl' ) ? '↙' : '↘';
}
return mw.html.element( 'span', {'class': cssClass, title: msg( tooltipMsg )}, arrow );
}
/**
* formats a period of time
* @param hours {number} hours
* @return {string} formatted period
*/
function formatPeriod ( hours ) {
var dayString = '', hourString = '', minuteString = '';
if ( hours >= 24 ) {
var days = Math.floor( hours / 24 );
hours -= days * 24;
hours = Math.round( hours );
if ( hours === 24 ) {
days += 1;
hours = 0;
}
dayString = msg( 'days', days );
if ( hours > 0 ) {
hourString = ' ' + msg( 'hours', hours );
}
return dayString + hourString;
} else {
var wholeHours = Math.floor( hours ),
minutes = Math.round( 60 * ( hours - wholeHours ) );
if ( minutes === 60 ) {
wholeHours += 1;
minutes = 0;
}
if ( wholeHours > 0 ) {
hourString = msg( 'hours', wholeHours );
}
if ( wholeHours === 0 || minutes > 0 ) {
minuteString = msg( 'minutes', minutes );
}
if ( hourString !== '' && minuteString !== '' ) {
hourString += ' ';
}
return hourString + minuteString;
}
}
// main
/**
* This function gets all recent changes in the namespaces starting at the start time.
* After the last API call has been done it will call the callback function
* @param end {string} end time (timestamp)
* @param namespaces {string} namespaces to show, either empty for all or something like '0|1|5'
* @param maxcalls {number} maximal number of API calls
* @param callback {function} function after the last API call, called with one parameter:
* true if all edits until end were retrieved, false if aborted earlier
* @param start {string} start time (timestamp), leave empty for first call
*/
function getAPIRecentChanges ( end, namespaces, maxcalls, callback, start ) {
var data = {
action: 'query',
rawcontinue: '',
list: 'recentchanges',
rcend: end,
rclimit: 'max',
rcprop: 'user|comment|title|sizes|flags|timestamp',
rctype: 'edit|new',
format: 'json'
};
if ( start ) {
data.rcstart = start;
} else {
data.meta = 'siteinfo';
data.siprop = 'general';
}
if ( namespaces ) {
data.rcnamespace = namespaces;
}
$.getJSON( mw.util.wikiScript( 'api' ), data, function ( json ) {
if ( json && json.query && json.query.general ) {
currTime = getTime( json.query.general.time );
}
if ( json && json.query && json.query.recentchanges ) {
var rc = json.query.recentchanges;
for ( var i = 0; i < rc.length; i++ ) {
var edit = rc[i];
if ( !( edit.title in pagesList ) ) {
pagesList[edit.title] = {
newsize: edit.newlen, // the first is the latest edit, so newlen is the most recent size
edits: 0,
minor: 0,
users: [],
anons: 0,
time: 0,
sections: {}
};
}
var section = /^\/\*\s*(.*?)\s*\*\//.exec( edit.comment ); // title of the section
if ( section ) {
section = section[1];
}
if ( section ) {
if ( !( section in pagesList[edit.title].sections ) ) {
pagesList[edit.title].sections[section] = {
edits: 0,
minor: 0,
users: [],
anons: 0,
time: 0
};
}
}
var time = getTime( edit.timestamp );
firstTime = time;
pagesList[edit.title].edits++; // increment edits
if ( section ) {
pagesList[edit.title].sections[section].edits++;
}
if ( edit.minor === '' ) { // increment minor edits
pagesList[edit.title].minor++;
if ( section ) {
pagesList[edit.title].sections[section].minor++;
}
}
pagesList[edit.title].oldsize = edit.oldlen; // update oldlen for every edit, only the earliest (= last) is interesting
if ( $.inArray( edit.user, pagesList[edit.title].users ) === -1 ) { // store if new user
pagesList[edit.title].users.push( edit.user );
if ( edit.anon === '' ) {
pagesList[edit.title].anons++;
}
}
if ( section ) {
if ( $.inArray( edit.user, pagesList[edit.title].sections[section].users ) === -1 ) {
pagesList[edit.title].sections[section].users.push( edit.user );
if ( edit.anon === '' ) {
pagesList[edit.title].sections[section].anons++;
}
}
}
pagesList[edit.title].time += (time - currTime);
if ( section ) {
pagesList[edit.title].sections[section].time += (time - currTime);
}
}
}
if ( json && json['query-continue'] && json['query-continue'].recentchanges ) {
if ( maxcalls > 1 ) {
getAPIRecentChanges( end, namespaces, maxcalls - 1, callback, json['query-continue'].recentchanges.rcstart );
} else {
callback( false );
}
} else {
callback( true );
}
} );
}
/**
* get the pages/sections with the most edits
* @param data {object} data about the number of edits, entries must have the form
* 'Name': {edits: 123}
* @param count {number} number of pages/sections to get
* @param edits {number} number of edits needed at least to output a page/section
* @return {array} list of the pages/sections with the most edits (decreasing order)
*/
function getMostEdited ( data, count, edits ) {
var items = [];
for ( var item in data ) {
items.push( item );
}
items.sort( function ( a, b ) {
return data[b].edits - data[a].edits;
} );
var output = items.slice( 0, count );
while ( output.length > 0 && data[output[output.length - 1]].edits < edits ) {
output.pop();
}
return output;
}
// functions generating HTML
/**
* get HTML for one entry
* @param page {string} name of the page to get HTML for
* @param count {number} number of sections to show
* @param edits {number} number of edits a section must have at least
* @return {string} HTML
*/
function generatePageHTML ( page, count, edits ) {
var data = pagesList[page],
html = mw.html.element( 'h2', {}, new mw.html.Raw(
mw.html.element( 'a', {href: mw.util.getUrl( page ), title: page}, page ) +
getTrend( data ) ) );
html += mw.html.element( 'ul', {}, new mw.html.Raw(
mw.html.element( 'li', {}, new mw.html.Raw(
msg( 'mostedited-edits', data.edits, data.minor ) ) ) +
mw.html.element( 'li', {}, new mw.html.Raw(
msg( 'mostedited-users', data.users.length, data.anons ) ) ) +
mw.html.element( 'li', {}, new mw.html.Raw(
//FIXME: showCharacterDifference returns an HTML fragment which is escaped by the parser from mediawiki.jqueryMsg.js in MediaWiki 1.19+,
//but not in 1.18. Since the parser from mediawiki.js never escapes HTML (at least not in 1.19 or earlier) use mw.msg here instead of msg.
mw.msg( 'mostedited-size', showCharacterDifference( data.newsize - data.oldsize ) ) ) ) ) );
var sections = getMostEdited( data.sections, count, edits );
for ( var i = 0; i < sections.length; i++ ) {
var section = sections[i], sectionData = data.sections[section];
html += mw.html.element( 'h3', {}, new mw.html.Raw(
mw.html.element( 'a',
{href: mw.util.getUrl( page ) + '#' + encodeSectionLink( section )},
section ) +
getTrend( sectionData ) ) );
html += mw.html.element( 'ul', {}, new mw.html.Raw(
mw.html.element( 'li', {}, new mw.html.Raw( msg( 'mostedited-edits', sectionData.edits, sectionData.minor ) ) ) +
mw.html.element( 'li', {}, new mw.html.Raw( msg( 'mostedited-users', sectionData.users.length, sectionData.anons ) ) ) ) );
}
return html;
}
/**
* get HTML for complete list
* @param countPages {number} number of pages to show
* @param countSections {number} number of sections to show for each page
* @param editPages {number} number of edits a page must have at least
* @param editSections {number} number of edits a section must have at least
* @return {string} HTML
*/
function generateHTML ( countPages, countSections, editPages, editSections ) {
var pages = getMostEdited ( pagesList, countPages, editPages ),
html = '';
if ( pages.length === 0 ) {
html += msg( 'mostedited-no-pages', editPages );
} else {
for ( var i = 0; i < pages.length; i++ ) {
html += generatePageHTML( pages[i], countSections, editSections );
}
}
return html;
}
/**
* get HTML for header
* @return {string} HTML
*/
function generateHeaderHTML () {
$( '#firstHeading' ).text( msg( 'mostedited' ) );
var i,
html = '',
legend = '',
labelTime = '',
selectTime = '',
labelNamespaces = '',
selectNamespaces = '',
invert = '',
associated = '',
submit = '',
hours,
times = [],
optionsTime = [],
optionsNamespaces = [],
formattedNamespaces = mw.config.get( 'wgFormattedNamespaces' );
legend = mw.html.element( 'legend', {}, msg( 'mostedited-legend' ) );
labelTime = mw.html.element( 'label', {'for': 'time'}, msg( 'mostedited-time' ) );
hours = parseFloat( mw.util.getParamValue( 'hours' ) || '0', 10 );
if ( hours <= 0 ) {
hours = 1;
}
times = [0.25, 0.5, 1, 2, 24];
if ( $.inArray( hours, times ) === -1 ) {
times.push( hours );
times.sort( function ( a, b ) {
return a - b;
} );
}
for ( i = 0; i < times.length; i++ ) {
optionsTime.push( mw.html.element( 'option',
{value: times[i], selected: times[i] === hours},
formatPeriod( times[i] ) ) );
}
selectTime = mw.html.element( 'select',
{id: 'time', name: 'time', 'class': 'timeselector'},
new mw.html.Raw( optionsTime.join( '' ) ) );
labelNamespaces = mw.html.element( 'label', {'for': 'namespace'}, msg( 'namespace' ) );
optionsNamespaces.push( mw.html.element( 'option', {value: ''}, msg( 'namespacesall' ) ) );
for ( i in formattedNamespaces ) {
if ( i < 0 ) {
continue;
}
var namespace = formattedNamespaces[i];
if ( namespace === '' ) {
namespace = msg( 'blanknamespace' );
}
optionsNamespaces.push( mw.html.element( 'option',
{value: i, selected: mw.util.getParamValue( 'namespace' ) === i}, // both are strings
namespace ) );
}
selectNamespaces = mw.html.element( 'select',
{id: 'namespace', name: 'namespace', 'class': 'namespaceselector'},
new mw.html.Raw( optionsNamespaces.join( '' ) ) );
invert = mw.html.element( 'input',
{name: 'invert', value: 1, id: 'nsinvert', type: 'checkbox', title: msg( 'tooltip-invert' ),
checked: mw.util.getParamValue( 'invert' ) === '1'} ) +
' ' +
mw.html.element( 'label', {'for': 'nsinvert', title: msg( 'tooltip-invert' )}, msg( 'invert' ) );
associated = mw.html.element( 'input',
{name: 'associated', value: 1, id: 'nsassociated', type: 'checkbox', title: msg( 'tooltip-namespace_association' ),
checked: mw.util.getParamValue( 'associated' ) === '1'} ) +
' ' +
mw.html.element( 'label',
{'for': 'nsassociated', title: msg( 'tooltip-namespace_association' )},
msg( 'namespace_association' ) );
submit = mw.html.element( 'input', {type: 'button', id: 'submitButton', value: msg( 'allpagessubmit' )} );
html += '<fieldset class="rcoptions">' + // structure copied from HTML of Special:RecentChanges
legend +
'<table class="mw-recentchanges-table"><tbody><tr><td class="mw-label">' +
labelTime +
'</td><td class="mw-input">' +
selectTime +
' <span id="mostedited-real-time"></span>' +
'</td></tr><tr><td class="mw-label">' +
labelNamespaces +
'</td><td class="mw-input">' +
selectNamespaces +
' ' +
invert +
' ' +
associated +
' ' +
submit +
'</td></tr></tbody></table></fieldset>';
html += mw.html.element( 'div', {id: 'mostEditedContainer'} );
return html;
}
// functions to interact with user
/**
* reads user input from form elements and URL, sets default
* @return {object} object with all parameters
*/
function readUserInput () {
var namespace = $( '#namespace option:selected' ).val(),
invert = $( '#nsinvert' ).prop( 'checked' ),
associated = $( '#nsassociated' ).prop( 'checked' ),
namespaces,
hours = $( '#time option:selected' ).val(),
ago = new Date( ( new Date() ).getTime() - ( hours * 3600000 ) ),
end = String( ago.getUTCFullYear() ) + '-' +
String( ago.getUTCMonth() + 101 ).substr( 1 ) + '-' +
String( ago.getUTCDate() + 100 ).substr( 1 ) + 'T' +
String( ago.getUTCHours() + 100 ).substr ( 1 ) + ':' +
String( ago.getUTCMinutes() + 100 ).substr( 1 ) + ':' +
String( ago.getUTCSeconds() + 100 ).substr( 1 ) + 'Z';
if ( namespace === '' ) {
namespaces = ''; // all
} else {
namespace = Number( namespace );
var list = [namespace];
if ( associated ) {
list.push(
( namespace % 2 === 0 ) ?
namespace + 1 :
namespace - 1 );
}
if ( invert ) {
namespaces = [];
var formattedNamespaces = mw.config.get( 'wgFormattedNamespaces' );
for ( var i in formattedNamespaces ) {
if ( i >= 0 && $.inArray( Number( i ), list ) === -1 ) {
namespaces.push( i );
}
}
namespaces = namespaces.join( '|' );
} else {
namespaces = list.join( '|' );
}
}
return {
namespaces: namespaces,
end: end,
maxCalls: mw.util.getParamValue( 'max-calls' ) || 5,
limit: mw.util.getParamValue( 'limit' ) || 10,
sectionLimit: mw.util.getParamValue( 'section-limit' ) || 3,
edits: mw.util.getParamValue( 'edits' ) || 2,
sectionEdits: mw.util.getParamValue( 'section-edits' ) || 2
};
}
/**
* called when user clicks submit button
*/
function submitQuery () {
var params = readUserInput();
$( '#submitButton' ).prop( 'disabled', true );
// $( '#mostEditedContainer' ).empty().injectSpinner( 'mostedited' ); This needs MW 1.19, so use old wikibits.js
window.injectSpinner( $( '#mostEditedContainer' ).empty().get( 0 ), 'mostedited' );
pagesList = {}; // empty
getAPIRecentChanges( params.end, params.namespaces, params.maxCalls, function ( done ) {
var $realTime = $( '#mostedited-real-time' );
if ( done ) {
firstTime = getTime( params.end );
$realTime.text( '' );
} else {
$realTime.html( mw.html.element( 'span',
{title: msg( 'mostedited-changed-period-tooltip' )},
msg( 'mostedited-changed-period', formatPeriod( ( currTime - firstTime ) / 3600000 ) ) ) );
}
$( '#mostEditedContainer' ).html( generateHTML( params.limit, params.sectionLimit, params.edits, params.sectionEdits ) );
// $.removeSpinner( 'mostedited' ); This needs MW 1.19, so use old wikibits.js
window.removeSpinner( 'mostedited' );
$( '#submitButton' ).prop( 'disabled', false );
} );
}
// initialise
/**
* initialises the interface on Special:Blankpage
*/
function initBlankpage () {
document.title = msg( 'pagetitle', msg( 'mostedited' ) );
var $content = mw.util.$content.children( 'p' ); // don't clear away subtitle, newtalk and jumpto
if ( $content.length !== 1 ) {
$content = mw.util.$content;
}
$content.html( generateHeaderHTML() );
mw.loader.load( 'mediawiki.special.recentchanges' ); // enables/disables checkboxes
$( '#submitButton' ).click( submitQuery ).click();
}
/**
* initialises the interface on Special:RecentChanges
*/
function initRecentchanges () {
var $button = $( mw.html.element( 'input', {type: 'button', value: msg( 'mostedited-submit' )} ) )
.click( function () {
var namespace = $( '#namespace option:selected' ).val(),
invert = $( '#nsinvert' ).prop( 'checked' ) ? '1' : '0',
associated = $( '#nsassociated' ).prop( 'checked' ) ? '1' : '0';
document.location.href = mw.util.getUrl( 'Special:BlankPage' ) + '?' +
$.param( {action: 'mostedited', namespace: namespace, invert: invert, associated: associated} );
} );
$( 'input[type="submit"]' ).eq( 0 ).after( $button ); // FIXME breaks when there is another submit button before it
}
/**
* initialises the sidebar everywhere
*/
function initSidebar () {
var portlet = $( '#n-recentchanges' ).parents( '.portlet, .portal' ).attr( 'id' ) || 'p-navigation';
mw.util.addPortletLink( portlet,
mw.util.getUrl( 'Special:BlankPage' ) + '?action=mostedited',
msg( 'mostedited' ),
'n-mostedited',
msg( 'tooltip-n-mostedited' ),
null, // access key
'#n-recentchanges' );
}
$( initSidebar );
if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Recentchanges' ) {
$( initRecentchanges );
}
if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Blankpage' &&
mw.util.getParamValue( 'action' ) === 'mostedited' )
{
mw.loader.using( [ 'mediawiki.jqueryMsg' /*, 'jquery.spinner' this needs MW 1.19 */ ],
function () {
/**
* replace msg with a version that handles {{SITENAME}} and {{PLURAL:}}
* this is only needed here, not in the other cases, where the original mw.msg is just fine
* @TODO remove this once MediaWiki handles this itself
*/
msg = mw.jqueryMsg.getMessageFunction( {
magic: {
'SITENAME': mw.config.get( 'wgSiteName' )
}
} );
$( initBlankpage );
} );
}
} )( jQuery );
// </nowiki>