mediawiki-extensions-Visual.../modules/ve-mw/ui/pages/ve.ui.MWAddParameterPage.js
Andrew Kostka a38338259d Improve input validation for the add parameter page
This patch improves the error handling for when a user tries to add
a parameter which is either an alias of a existing parameter, the
primary name of a existing aliased parameter, or a name/alias of an
existing parameter which is shown with an override label.

The error message was modified to always refer to the conflicting
parameter using the same name that is has in the sidebar.

Example: A parameter named "Parameter B" is already present in the
sidebar under its alias "B". When a user tries to add "Parameter B",
the new error message will inform the user that the parameter they
are trying to add already exists as "B".

Bug: T285869
Change-Id: I762b72b6cf14eb8ff5fcef63b4dcb70e297050de
2021-09-13 16:58:11 +02:00

204 lines
5.9 KiB
JavaScript

/**
* Placeholder page for a currently unnamed parameter. Represented as a unnamed
* {@see ve.dm.MWParameterModel} in the corresponding {@see ve.dm.MWTemplateModel}.
*
* @class
* @extends OO.ui.PageLayout
*
* @constructor
* @param {ve.dm.MWParameterModel} parameter Reference to a placeholder parameter with an empty
* name, as well as to the template the parameter belongs to
* @param {string} name Unique symbolic name of page
* @param {Object} [config] Configuration options
* @cfg {jQuery} [$overlay] Overlay to render dropdowns in
*/
ve.ui.MWAddParameterPage = function VeUiMWAddParameterPage( parameter, name, config ) {
// Parent constructor
ve.ui.MWAddParameterPage.super.call( this, name, ve.extendObject( {
scrollable: false
}, config ) );
this.template = parameter.getTemplate();
this.isExpanded = false;
// Header button to expand
this.addParameterInputHeader = new OO.ui.ButtonWidget( {
label: ve.msg( 'visualeditor-dialog-transclusion-add-undocumented-param' ),
icon: 'add',
framed: false,
inline: true,
classes: [ 've-ui-mwTransclusionDialog-addParameterFieldset-header' ]
} )
.connect( this, { click: 'togglePlaceholder' } );
// Input field and button
this.paramInputField = new OO.ui.TextInputWidget( {
placeholder: ve.msg( 'visualeditor-dialog-transclusion-add-param-placeholder' )
} )
.connect( this, {
change: 'onParameterNameChanged',
enter: 'onParameterNameSubmitted'
} );
this.saveButton = new OO.ui.ButtonWidget( {
label: ve.msg( 'visualeditor-dialog-transclusion-add-param-save' ),
flags: [ 'primary', 'progressive' ],
disabled: true
} )
.connect( this, { click: 'onParameterNameSubmitted' } );
this.addParameterInputField = new OO.ui.ActionFieldLayout(
this.paramInputField,
this.saveButton,
{ classes: [ 've-ui-mwTransclusionDialog-addParameterFieldset-input' ] }
);
var link = this.template.getTitle() || this.template.getTarget().wt;
var $helpText = mw.message(
'visualeditor-dialog-transclusion-add-param-help',
link
).parseDom();
ve.init.platform.linkCache.styleElement( link, $helpText );
this.addParameterFieldset = new OO.ui.FieldsetLayout( {
label: this.addParameterInputHeader.$element,
helpInline: true,
help: $helpText,
classes: [ 've-ui-mwTransclusionDialog-addParameterFieldset' ],
$content: this.addParameterInputField.$element
} );
ve.targetLinksToNewWindow( this.addParameterFieldset.$element[ 0 ] );
// Init visibility
this.togglePlaceholder( false );
// Initialization
this.$element
.addClass( 've-ui-mwParameterPlaceholderPage' )
.append( this.addParameterFieldset.$element );
};
/* Inheritance */
OO.inheritClass( ve.ui.MWAddParameterPage, OO.ui.PageLayout );
/* Methods */
/**
* @inheritDoc OO.ui.PanelLayout
*/
ve.ui.MWAddParameterPage.prototype.focus = function () {
if ( this.isExpanded ) {
this.paramInputField.focus();
return;
}
// Parent method
ve.ui.MWAddParameterPage.super.prototype.focus.apply( this, arguments );
};
/**
* @private
* @param {string} value
*/
ve.ui.MWAddParameterPage.prototype.onParameterNameChanged = function ( value ) {
var paramName = value.trim(),
errors = this.getValidationErrors( paramName );
this.addParameterInputField.setErrors( errors );
this.saveButton.setDisabled( !paramName || errors.length );
};
/**
* @private
*/
ve.ui.MWAddParameterPage.prototype.onParameterNameSubmitted = function () {
var name = this.paramInputField.getValue().trim();
if ( !name || this.saveButton.isDisabled() ) {
return;
}
this.paramInputField.setValue( '' );
if ( this.template.hasParameter( name ) ) {
return;
}
var param = new ve.dm.MWParameterModel( this.template, name );
this.template.addParameter( param );
this.emit( 'focusTemplateParameterById', param.getId() );
ve.track( 'activity.transclusion', {
action: 'add-unknown-parameter'
} );
};
/**
* @private
* @param {string} name Parameter name or alias
* @return {jQuery[]} An array as accepted by {@see OO.ui.FieldLayout.setErrors}
*/
ve.ui.MWAddParameterPage.prototype.getValidationErrors = function ( name ) {
if ( !name ) {
return [];
}
var forbiddenCharacter = name.match( /[={|}]/ );
if ( forbiddenCharacter ) {
return [ mw.message( 'visualeditor-dialog-transclusion-add-param-error-forbidden-char',
forbiddenCharacter[ 0 ] ).parseDom() ];
}
var key,
spec = this.template.getSpec();
if ( spec.getParameterAliases( name ).indexOf( name ) !== -1 ) {
key = 'visualeditor-dialog-transclusion-add-param-error-alias';
} else if ( this.template.hasParameter( name ) ) {
key = 'visualeditor-dialog-transclusion-add-param-error-exists-selected';
} else if ( spec.isParameterDeprecated( name ) ) {
key = 'visualeditor-dialog-transclusion-add-param-error-deprecated';
} else if ( spec.isKnownParameterOrAlias( name ) ) {
key = 'visualeditor-dialog-transclusion-add-param-error-exists-unselected';
}
if ( !key ) {
return [];
}
var label = spec.getParameterLabel( this.template.getOriginalParameterName( name ) ),
// eslint-disable-next-line mediawiki/msg-doc
$msg = mw.message( key, name, label ).parseDom();
ve.targetLinksToNewWindow( $( '<div>' ).append( $msg )[ 0 ] );
return [ $msg ];
};
/**
* @private
* @param {boolean} [expand]
*/
ve.ui.MWAddParameterPage.prototype.togglePlaceholder = function ( expand ) {
this.isExpanded = expand === undefined ? !this.isExpanded : !!expand;
this.addParameterInputHeader.setIcon( this.isExpanded ? 'subtract' : 'add' );
this.addParameterFieldset.$element.toggleClass(
've-ui-mwTransclusionDialog-addParameterFieldset-collapsed',
!this.isExpanded
);
if ( this.isExpanded ) {
this.paramInputField.focus();
}
};
/**
* @inheritDoc OO.ui.PageLayout
*/
ve.ui.MWAddParameterPage.prototype.setOutlineItem = function () {
// Parent method
ve.ui.MWAddParameterPage.super.prototype.setOutlineItem.apply( this, arguments );
if ( this.outlineItem ) {
// This page should not be shown in the (BookletLayout-based) sidebar
this.outlineItem.$element.empty().removeAttr( 'class' );
}
};