diff --git a/extension.json b/extension.json index 432ddb4e3c..76e02b90d2 100644 --- a/extension.json +++ b/extension.json @@ -2174,6 +2174,7 @@ ], "messages": [ "quotation-marks", + "redirectedfrom", "templatedata-doc-subpage", "visualeditor-changedesc-mwtransclusion", "visualeditor-dialog-template-title", diff --git a/modules/ve-mw/tests/ui/widgets/ve.ui.MWTemplateTitleInputWidget.test.js b/modules/ve-mw/tests/ui/widgets/ve.ui.MWTemplateTitleInputWidget.test.js index 2d0713a379..884890ea24 100644 --- a/modules/ve-mw/tests/ui/widgets/ve.ui.MWTemplateTitleInputWidget.test.js +++ b/modules/ve-mw/tests/ui/widgets/ve.ui.MWTemplateTitleInputWidget.test.js @@ -1,7 +1,7 @@ ( function () { function enableCirrusSearchLookup( enabled ) { const config = mw.config.get( 'wgVisualEditorConfig' ); - config.cirrusSearchLookup = enabled; + config.cirrusSearchLookup = enabled !== false; mw.config.set( 'wgVisualEditorConfig', config ); } @@ -29,7 +29,7 @@ } ); QUnit.test( 'CirrusSearch: all API parameters', ( assert ) => { - enableCirrusSearchLookup( true ); + enableCirrusSearchLookup(); const widget = new ve.ui.MWTemplateTitleInputWidget(), query = 'a', apiParams = widget.getApiParams( query ); @@ -39,6 +39,7 @@ generator: 'search', gsrlimit: 10, gsrnamespace: 10, + gsrprop: 'redirecttitle', gsrsearch: 'a*', ppprop: 'disambiguation', prop: [ 'info', 'pageprops' ], @@ -46,8 +47,16 @@ } ); } ); + QUnit.test( 'CirrusSearch: showRedirectTargets disabled', ( assert ) => { + enableCirrusSearchLookup(); + const widget = new ve.ui.MWTemplateTitleInputWidget( { showRedirectTargets: false } ), + apiParams = widget.getApiParams(); + + assert.notOk( 'gsrprop' in apiParams ); + } ); + QUnit.test( 'CirrusSearch: prefixsearch behavior', ( assert ) => { - enableCirrusSearchLookup( true ); + enableCirrusSearchLookup(); const widget = new ve.ui.MWTemplateTitleInputWidget(); [ @@ -77,4 +86,31 @@ ); } ); } ); + + QUnit.test( 'CirrusSearch: redirect is forwarded to the TitleOptionWidget', ( assert ) => { + enableCirrusSearchLookup(); + const widget = new ve.ui.MWTemplateTitleInputWidget(), + originalData = { redirecttitle: 'Template:From' }, + data = widget.getOptionWidgetData( 'Template:To', { originalData } ); + + assert.strictEqual( data.redirecttitle, 'Template:From' ); + } ); + + QUnit.test( 'CirrusSearch: redirect appears in the description', ( assert ) => { + enableCirrusSearchLookup(); + const widget = new ve.ui.MWTemplateTitleInputWidget(); + + let option = widget.createOptionWidget( { redirecttitle: 'Template:From' } ); + assert.strictEqual( + option.$element.find( '.ve-ui-mwTemplateTitleInputWidget-redirectedfrom' ).text(), + '(redirectedfrom: From)' + ); + + widget.relative = false; + option = widget.createOptionWidget( { redirecttitle: 'Template:From' } ); + assert.strictEqual( + option.$element.find( '.ve-ui-mwTemplateTitleInputWidget-redirectedfrom' ).text(), + '(redirectedfrom: Template:From)' + ); + } ); }() ); diff --git a/modules/ve-mw/ui/styles/dialogs/ve.ui.MWTransclusionDialog.css b/modules/ve-mw/ui/styles/dialogs/ve.ui.MWTransclusionDialog.css index 5a378b82be..386499196d 100644 --- a/modules/ve-mw/ui/styles/dialogs/ve.ui.MWTransclusionDialog.css +++ b/modules/ve-mw/ui/styles/dialogs/ve.ui.MWTransclusionDialog.css @@ -46,6 +46,10 @@ font-weight: normal; } +.ve-ui-mwTemplateTitleInputWidget-redirectedfrom { + font-style: italic; +} + .ve-ui-mwTemplateDialog .oo-ui-outlineOptionWidget.oo-ui-flaggedElement-empty .oo-ui-iconElement-icon { opacity: 0.51; } diff --git a/modules/ve-mw/ui/widgets/ve.ui.MWTemplateTitleInputWidget.js b/modules/ve-mw/ui/widgets/ve.ui.MWTemplateTitleInputWidget.js index e27674b34d..3a8f6eb711 100644 --- a/modules/ve-mw/ui/widgets/ve.ui.MWTemplateTitleInputWidget.js +++ b/modules/ve-mw/ui/widgets/ve.ui.MWTemplateTitleInputWidget.js @@ -48,17 +48,22 @@ ve.ui.MWTemplateTitleInputWidget.prototype.getApiParams = function ( 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; + ve.extendObject( params, { + generator: 'search', + gsrsearch: params.gpssearch, + // gsrsort: 'incoming_links_desc', + gsrnamespace: params.gpsnamespace, + gsrlimit: params.gpslimit + } ); // Searching for "foo *" is pointless. Don't normalize it to "foo*" either but leave it // unchanged. This makes the word "foo" behave the same in "foo " and "foo bar". In both // cases it's not considered a prefix any more. if ( !/\s$/.test( params.gsrsearch ) ) { params.gsrsearch += '*'; } - // params.gsrsort = 'incoming_links_desc'; - params.gsrnamespace = params.gpsnamespace; - params.gsrlimit = params.gpslimit; + if ( this.showRedirectTargets ) { + params.gsrprop = 'redirecttitle'; + } delete params.gpssearch; delete params.gpsnamespace; delete params.gpslimit; @@ -168,10 +173,38 @@ ve.ui.MWTemplateTitleInputWidget.prototype.getLookupRequest = function () { .promise( { abort: function () {} } ); }; -// @inheritdoc mw.widgets.TitleInputWidget -ve.ui.MWTemplateTitleInputWidget.prototype.getOptionWidgetData = function ( title ) { +// @inheritdoc mw.widgets.TitleWidget +ve.ui.MWTemplateTitleInputWidget.prototype.getOptionWidgetData = function ( title, data ) { return ve.extendObject( ve.ui.MWTemplateTitleInputWidget.super.prototype.getOptionWidgetData.apply( this, arguments ), - { description: this.descriptions[ title ] } + { + description: this.descriptions[ title ], + redirecttitle: data.originalData.redirecttitle + } ); }; + +// @inheritdoc mw.widgets.TitleWidget +ve.ui.MWTemplateTitleInputWidget.prototype.createOptionWidget = function ( data ) { + var widget = ve.ui.MWTemplateTitleInputWidget.super.prototype.createOptionWidget.call( this, data ); + + if ( data.redirecttitle ) { + // Same conditions as in mw.widgets.TitleWidget.getOptionWidgetData() + var title = new mw.Title( data.redirecttitle ), + text = this.namespace !== null && this.relative ? + title.getRelativeText( this.namespace ) : + data.redirecttitle; + + var $desc = widget.$element.find( '.mw-widget-titleOptionWidget-description' ); + if ( !$desc.length ) { + $desc = $( '' ) + .addClass( 'mw-widget-titleOptionWidget-description' ) + .appendTo( widget.$element ); + } + $desc.prepend( $( '
' ) + .addClass( 've-ui-mwTemplateTitleInputWidget-redirectedfrom' ) + .text( mw.msg( 'redirectedfrom', text ) ) ); + } + + return widget; +};