aboutsummaryrefslogtreecommitdiffstats
path: root/resources/src/mediawiki.page.preview.js
diff options
context:
space:
mode:
authorSam Wilson <sam@samwilson.id.au>2023-03-21 11:41:01 +0800
committerSam Wilson <sam@samwilson.id.au>2023-03-29 16:54:07 +0800
commitcbbe7e31e6a5fea693b49d2eec03a2f3577f9f36 (patch)
tree08f0713c179282d0d4ef5a7dfc85d35f1a98f3de /resources/src/mediawiki.page.preview.js
parent77cd7c149adef81c32ad1eb7c059b4da8aecdeb5 (diff)
downloadmediawikicore-cbbe7e31e6a5fea693b49d2eec03a2f3577f9f36.tar.gz
mediawikicore-cbbe7e31e6a5fea693b49d2eec03a2f3577f9f36.zip
page.preview: batch requests for template list with max 50 titles
For pages with more than 50 or 500 templates (depending on user rights), the list of templates that is shown on live preview was not updating correctly. This fixes the bug by splitting the templates into batches of 50 and sending multiple requests. Bug: T321032 Change-Id: I169c19f6e75f884f270d6d126c74982c79295053
Diffstat (limited to 'resources/src/mediawiki.page.preview.js')
-rw-r--r--resources/src/mediawiki.page.preview.js83
1 files changed, 55 insertions, 28 deletions
diff --git a/resources/src/mediawiki.page.preview.js b/resources/src/mediawiki.page.preview.js
index 7c4f491f9a9a..b222b54cba7b 100644
--- a/resources/src/mediawiki.page.preview.js
+++ b/resources/src/mediawiki.page.preview.js
@@ -125,31 +125,59 @@
// Otherwise, fetch protection status of all templates.
$parent.addClass( 'mw-preview-loading-elements-loading' );
- api.post( {
- action: 'query',
- format: 'json',
- titles: templates.map( function ( template ) { return template.title; } ).join( '|' ),
- prop: 'info',
- // @todo Do we need inlinkcontext here?
- inprop: 'linkclasses|protection',
- intestactions: 'edit'
- } ).done( function ( response ) {
- // Empty the list in preparation for either adding new items or not needing to.
+
+ // Batch titles because API is limited to 50 at a time.
+ var batchSize = 50;
+ var requests = [];
+ for ( var batch = 0; batch < templates.length; batch += batchSize ) {
+ // Build a pipe-separated list of template names for this batch.
+ var titles = templates
+ .slice( batch, batch + batchSize )
+ .map( function ( template ) { return template.title; } )
+ .join( '|' );
+ requests.push( api.post( {
+ action: 'query',
+ format: 'json',
+ formatversion: 2,
+ titles: titles,
+ prop: 'info',
+ // @todo Do we need inlinkcontext here?
+ inprop: 'linkclasses|protection',
+ intestactions: 'edit'
+ } ) );
+ }
+ $.when.apply( null, requests ).done( function () {
+ var templatesAllInfo = [];
+ // For the first batch, empty the list in preparation for either adding new items or not needing to.
+ // @todo Don't empty the list till the new list items are ready to be inserted.
$list.empty();
+ for ( var r = 0; r < arguments.length; r++ ) {
+ // Response is either the whole argument, or the 0th element of it.
+ var response = arguments[ r ][ 0 ] || arguments[ r ];
+ var templatesInfo = ( response.query && response.query.pages ) || [];
+ templatesInfo.forEach( function ( ti ) {
+ templatesAllInfo.push( {
+ title: mw.Title.newFromText( ti.title ),
+ apiData: ti
+ } );
+ } );
+ }
+ // Sort alphabetically.
+ templatesAllInfo.sort( function ( t1, t2 ) {
+ // Compare titles with the same rules of Title::compare() in PHP.
+ return t1.title.getNamespaceId() !== t2.title.getNamespaceId() ?
+ t1.title.getNamespaceId() > t2.title.getNamespaceId() :
+ t1.title.getMain().localeCompare( t2.title.getMain() );
+ } );
- var templatesInfo = ( response.query && response.query.pages ) || {};
+ // Add all templates to the list, and update the list header.
+ templatesAllInfo.forEach( function ( t ) {
+ addItemToTemplateList( $list, t );
+ } );
// The following messages can be used here:
// * templatesusedpreview
// * templatesusedsection
- $explanation.msg( explanationMsg, templatesInfo.length );
- if ( templatesInfo.length === 0 ) {
- return;
- }
-
- // Add all templates to the list, in the order they're returned by the API.
- Object.keys( templatesInfo ).forEach( function ( t ) {
- addItemToTemplateList( $list, templatesInfo[ t ] );
- } );
+ $explanation.msg( explanationMsg, templatesAllInfo.length );
} ).always( function () {
$parent.removeClass( 'mw-preview-loading-elements-loading' );
} );
@@ -164,10 +192,9 @@
* @return {void}
*/
function addItemToTemplateList( $list, template ) {
- var canEdit = template.actions.edit !== undefined;
- var title = mw.Title.newFromText( template.title );
- var linkClasses = template.linkclasses || [];
- if ( template.missing !== undefined ) {
+ var canEdit = template.apiData.actions.edit !== undefined;
+ var linkClasses = template.apiData.linkclasses || [];
+ if ( template.apiData.missing !== undefined ) {
linkClasses.push( 'new' );
}
var $baseLink = $( '<a>' )
@@ -178,13 +205,13 @@
// * any added by the GetLinkColours hook
.addClass( linkClasses );
var $link = $baseLink.clone()
- .attr( 'href', title.getUrl() )
- .text( title.getPrefixedText() );
+ .attr( 'href', template.title.getUrl() )
+ .text( template.title.getPrefixedText() );
var $editLink = $baseLink.clone()
- .attr( 'href', title.getUrl( { action: 'edit' } ) )
+ .attr( 'href', template.title.getUrl( { action: 'edit' } ) )
.append( mw.msg( canEdit ? 'editlink' : 'viewsourcelink' ) );
var wordSep = mw.message( 'word-separator' ).escaped();
- getRestrictionsText( template.protection || [] ).then( function ( restrictionsList ) {
+ getRestrictionsText( template.apiData.protection || [] ).then( function ( restrictionsList ) {
// restrictionsList is a comma-separated parentheses-wrapped localized list of restriction level names.
var editLinkParens = parenthesesWrap( $editLink[ 0 ].outerHTML );
var $li = $( '<li>' ).append( $link, wordSep, editLinkParens, wordSep, restrictionsList );