mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-17 03:18:48 +00:00
b15455ec3d
Template names sometimes show up twice when searching for a template in the "Add a template" dialog. This is a bit hard to test. The code responsible for this is not in a single place. The feature is in the upstream TitleWidget class. It's not broken. It makes sense to provide e.g. "foo" and "Foo" as two separate options when the user typed "foo", but the page is named "Foo". Both are valid, and the feature allows the user to pick either. But the VE widget does it's own normalization. Both entries are normalized to "Foo". Both do the same. The additional one is pointless. You can try this on the actual enwiki: Open VE, insert a template, search for "Template:nHLE". Change-Id: I65e706c4d131a2f8c605d7979a02ea56f831bf03
175 lines
5.8 KiB
JavaScript
175 lines
5.8 KiB
JavaScript
/*!
|
|
* VisualEditor UserInterface MWTemplateTitleInputWidget class.
|
|
*
|
|
* @copyright 2011-2020 VisualEditor Team and others; see AUTHORS.txt
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
*/
|
|
|
|
/**
|
|
* Creates an ve.ui.MWTemplateTitleInputWidget object.
|
|
*
|
|
* @class
|
|
* @extends mw.widgets.TitleInputWidget
|
|
*
|
|
* @constructor
|
|
* @param {Object} [config] Configuration options
|
|
* @cfg {number} [namespace] Namespace to prepend to queries. Defaults to template namespace.
|
|
*/
|
|
ve.ui.MWTemplateTitleInputWidget = function VeUiMWTemplateTitleInputWidget( config ) {
|
|
config = ve.extendObject( {}, {
|
|
namespace: mw.config.get( 'wgNamespaceIds' ).template,
|
|
// We don't need results to show up twice normalized and unnormalized
|
|
addQueryInput: false
|
|
}, config );
|
|
|
|
// Parent constructor
|
|
ve.ui.MWTemplateTitleInputWidget.super.call( this, config );
|
|
|
|
this.showTemplateDescriptions = this.showDescriptions;
|
|
// Clear the showDescriptions flag for subsequent requests as we implement
|
|
// description fetch ourselves
|
|
this.showDescriptions = false;
|
|
|
|
// Properties
|
|
this.descriptions = {};
|
|
|
|
// Initialization
|
|
this.$element.addClass( 've-ui-mwTemplateTitleInputWidget' );
|
|
};
|
|
|
|
/* Inheritance */
|
|
|
|
// FIXME: This should extend mw.widgets.TitleSearchWidget instead
|
|
OO.inheritClass( ve.ui.MWTemplateTitleInputWidget, mw.widgets.TitleInputWidget );
|
|
|
|
/* Methods */
|
|
|
|
// @inheritdoc mw.widgets.TitleWidget
|
|
ve.ui.MWTemplateTitleInputWidget.prototype.getApiParams = function ( query ) {
|
|
var params = ve.ui.MWTemplateTitleInputWidget.super.prototype.getApiParams.call( this, query );
|
|
|
|
// TODO: This should stay as a feature flag for 3rd-parties to fallback to prefixsearch
|
|
if ( mw.config.get( 'wgVisualEditorConfig' ).cirrusSearchLookup ) {
|
|
params.generator = 'search';
|
|
params.gsrsearch = params.gpssearch;
|
|
params.gsrsearch += '*';
|
|
// params.gsrsort = 'incoming_links_desc';
|
|
params.gsrnamespace = params.gpsnamespace;
|
|
params.gsrlimit = params.gpslimit;
|
|
delete params.gpssearch;
|
|
delete params.gpsnamespace;
|
|
delete params.gpslimit;
|
|
}
|
|
return params;
|
|
};
|
|
|
|
// @inheritdoc mw.widgets.TitleInputWidget
|
|
ve.ui.MWTemplateTitleInputWidget.prototype.getLookupRequest = function () {
|
|
var widget = this,
|
|
originalResponse,
|
|
templateDataMessage = mw.message( 'templatedata-doc-subpage' ),
|
|
templateDataInstalled = templateDataMessage.exists(),
|
|
templateDocPageFragment = '/' + templateDataMessage.text(),
|
|
promise = ve.ui.MWTemplateTitleInputWidget.super.prototype.getLookupRequest.call( this );
|
|
|
|
if ( !this.showTemplateDescriptions ) {
|
|
return promise;
|
|
}
|
|
|
|
return promise
|
|
.then( function ( response ) {
|
|
var xhr, pageId, redirIndex,
|
|
redirects = ( response.query && response.query.redirects ) || {},
|
|
origPages = ( response.query && response.query.pages ) || {},
|
|
newPages = [],
|
|
titles = [];
|
|
|
|
// Build a new array to replace response.query.pages, ensuring everything goes into
|
|
// the order defined by the page's index key, instead of whatever random order the
|
|
// browser would let you iterate over the old object in.
|
|
for ( pageId in origPages ) {
|
|
if ( 'index' in origPages[ pageId ] ) {
|
|
newPages[ origPages[ pageId ].index - 1 ] = origPages[ pageId ];
|
|
} else {
|
|
// Watch out for cases where the index is specified on the redirect object
|
|
// rather than the page object.
|
|
for ( redirIndex in redirects ) {
|
|
if ( redirects[ redirIndex ].to === origPages[ pageId ].title ) {
|
|
newPages[ redirects[ redirIndex ].index - 1 ] = origPages[ pageId ];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// T54448: Filter out matches which end in /doc or as configured on-wiki
|
|
if ( templateDataInstalled ) {
|
|
newPages = newPages.filter( function ( page ) {
|
|
// Can't use String.endsWith() as that's ES6.
|
|
// page.title.endsWith( templateDocPageFragment )
|
|
return page.title.slice( 0 - templateDocPageFragment.length ) !== templateDocPageFragment;
|
|
} );
|
|
} else {
|
|
// Even if not filtering /doc, collapse the sparse array
|
|
newPages = newPages.filter( function ( page ) {
|
|
return page;
|
|
} );
|
|
}
|
|
|
|
titles = newPages.map( function ( page ) {
|
|
return page.title;
|
|
} );
|
|
|
|
ve.setProp( response, 'query', 'pages', newPages );
|
|
originalResponse = response; // lie!
|
|
|
|
// Also get descriptions
|
|
// FIXME: This should go through MWTransclusionModel rather than duplicate.
|
|
if ( titles.length > 0 ) {
|
|
xhr = widget.getApi().get( {
|
|
action: 'templatedata',
|
|
format: 'json',
|
|
formatversion: 2,
|
|
titles: titles,
|
|
redirects: !!widget.showRedirects,
|
|
includeMissingTitles: '1',
|
|
lang: mw.config.get( 'wgUserLanguage' )
|
|
} );
|
|
return xhr.promise( { abort: xhr.abort } );
|
|
}
|
|
} )
|
|
.then( function ( templateDataResponse ) {
|
|
var index, page, missingTitle,
|
|
pages = ( templateDataResponse && templateDataResponse.pages ) || {};
|
|
// Look for descriptions and cache them
|
|
for ( index in pages ) {
|
|
page = pages[ index ];
|
|
|
|
if ( page.missing ) {
|
|
// Remmeber templates that don't exist in the link cache
|
|
// { title: { missing: true|false }
|
|
missingTitle = {};
|
|
missingTitle[ page.title ] = { missing: true };
|
|
ve.init.platform.linkCache.setMissing( missingTitle );
|
|
} else if ( !page.notemplatedata ) {
|
|
// Cache descriptions
|
|
widget.descriptions[ page.title ] = page.description;
|
|
}
|
|
}
|
|
// Return the original response
|
|
return originalResponse;
|
|
}, function () {
|
|
// API request failed; most likely, we're on a wiki which doesn't have TemplateData.
|
|
return originalResponse;
|
|
} )
|
|
.promise( { abort: function () {} } );
|
|
};
|
|
|
|
// @inheritdoc mw.widgets.TitleInputWidget
|
|
ve.ui.MWTemplateTitleInputWidget.prototype.getOptionWidgetData = function ( title ) {
|
|
return ve.extendObject(
|
|
ve.ui.MWTemplateTitleInputWidget.super.prototype.getOptionWidgetData.apply( this, arguments ),
|
|
{ description: this.descriptions[ title ] }
|
|
);
|
|
};
|