mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/TemplateData
synced 2024-11-23 23:43:54 +00:00
Add suggested values parameter
Parameters may include a `suggestedvalues` property, which is rendered in the UI for some parameter types. TemplateData editor UI elements are implemented behind the TemplateDataSuggestedValuesEditor feature flag. Bug: T271897 Change-Id: I14012c79b3fa0d48c58fd8999584cc03ec03575e
This commit is contained in:
parent
fef102d53c
commit
7b32bcefb4
|
@ -6,7 +6,7 @@
|
|||
https://phabricator.wikimedia.org/diffusion/ETDA/browse/master/Specification.md
|
||||
|
||||
**Editors**
|
||||
Timo Tijhof, Trevor Parscal, James D. Forrester, Marielle Volz, Moriel Schottlender, C.Scott Ananian, eranroz
|
||||
Timo Tijhof, Trevor Parscal, James D. Forrester, Marielle Volz, Moriel Schottlender, C.Scott Ananian, eranroz, Adam Wight
|
||||
|
||||
***
|
||||
|
||||
|
@ -199,7 +199,17 @@ The default value in wikitext (or description thereof) of a parameter as assumed
|
|||
|
||||
Consumers SHOULD indicate this default value to the user when inserting or editing a template.
|
||||
|
||||
#### 3.2.11 `example`
|
||||
#### 3.2.11 `suggestedvalues`
|
||||
* Value: `Array`
|
||||
* Default: `[]`
|
||||
|
||||
A list of commonly used, suggested values.
|
||||
|
||||
Consumers SHOULD provide this list to the user when filling out the field, but MAY implement suggested values only for some field types.
|
||||
|
||||
Consumers MUST allow the user to enter free-form values not on this list.
|
||||
|
||||
#### 3.2.12 `example`
|
||||
* Value: `null` or `InterfaceText`
|
||||
|
||||
An example text for the parameter, to help users fill in the proper value.
|
||||
|
|
|
@ -32,7 +32,8 @@
|
|||
"PageContentSave": "TemplateDataHooks::onPageContentSave",
|
||||
"ResourceLoaderRegisterModules": "TemplateDataHooks::onResourceLoaderRegisterModules",
|
||||
"EditPage::showEditForm:initial": "TemplateDataHooks::onEditPage",
|
||||
"ParserFetchTemplateData": "TemplateDataHooks::onParserFetchTemplateData"
|
||||
"ParserFetchTemplateData": "TemplateDataHooks::onParserFetchTemplateData",
|
||||
"MakeGlobalVariablesScript": "TemplateDataHooks::onMakeGlobalVariablesScript"
|
||||
},
|
||||
"MessagesDirs": {
|
||||
"TemplateData": [
|
||||
|
@ -149,6 +150,8 @@
|
|||
"templatedata-modal-table-param-actions",
|
||||
"templatedata-modal-table-param-aliases",
|
||||
"templatedata-modal-table-param-autovalue",
|
||||
"templatedata-modal-table-param-suggestedvalues",
|
||||
"templatedata-modal-table-param-suggestedvalues-placeholder",
|
||||
"templatedata-modal-table-param-default",
|
||||
"templatedata-modal-table-param-deprecated",
|
||||
"templatedata-modal-table-param-deprecatedValue",
|
||||
|
@ -232,6 +235,11 @@
|
|||
"config": {
|
||||
"TemplateDataUseGUI": {
|
||||
"value": true
|
||||
},
|
||||
"TemplateDataSuggestedValuesEditor": {
|
||||
"description": "Temporary feature flag to enable the \"suggested values\" UI",
|
||||
"value": false,
|
||||
"public": true
|
||||
}
|
||||
},
|
||||
"manifest_version": 2
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
"templatedata-doc-param-status-optional": "optional",
|
||||
"templatedata-doc-param-status-required": "required",
|
||||
"templatedata-doc-param-status-suggested": "suggested",
|
||||
"templatedata-doc-param-suggestedvalues": "Suggested values",
|
||||
"templatedata-doc-param-type": "Type",
|
||||
"templatedata-doc-param-type-boolean": "Boolean",
|
||||
"templatedata-doc-param-type-content": "Content",
|
||||
|
@ -101,6 +102,8 @@
|
|||
"templatedata-modal-table-param-name": "Name",
|
||||
"templatedata-modal-table-param-required": "Required",
|
||||
"templatedata-modal-table-param-suggested": "Suggested",
|
||||
"templatedata-modal-table-param-suggestedvalues": "Suggested values",
|
||||
"templatedata-modal-table-param-suggestedvalues-placeholder": "Add value...",
|
||||
"templatedata-modal-table-param-type": "Type",
|
||||
"templatedata-modal-table-param-uneditablefield": "Uneditable",
|
||||
"templatedata-modal-title": "Template documentation editor",
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
"templatedata-doc-param-status-optional": "Displayed when a template parameter is optional (should not be a full sentence, used in a table).\n{{Identical|Optional}}",
|
||||
"templatedata-doc-param-status-required": "Displayed when a template parameter is required (should not be a full sentence, used in a table).\n{{Identical|Required}}",
|
||||
"templatedata-doc-param-status-suggested": "Displayed when a template parameter is suggested (should not be a full sentence, used in a table).\n{{Identical|Suggested}}",
|
||||
"templatedata-doc-param-suggestedvalues": "Displayed when a template parameter has suggested values.\n{{Related|Templatedata-doc-param}}",
|
||||
"templatedata-doc-param-type": "Used as a column heading in the table.\n{{Identical|Type}}",
|
||||
"templatedata-doc-param-type-boolean": "A possible parameter type: Boolean\n{{Related|Templatedata-doc-param-type}}\n{{Identical|Boolean}}",
|
||||
"templatedata-doc-param-type-content": "A possible parameter type: Content\n{{Related|Templatedata-doc-param-type}}\n{{Identical|Content}}",
|
||||
|
@ -113,6 +114,8 @@
|
|||
"templatedata-modal-table-param-name": "Label for a parameter property input: Name of the parameter.\n{{Identical|Name}}",
|
||||
"templatedata-modal-table-param-required": "Label for a parameter property input: Required status of the parameter.\n{{Identical|Required}}",
|
||||
"templatedata-modal-table-param-suggested": "Label for a parameter property input: Suggested status of the parameter.\n{{Identical|Suggested}}",
|
||||
"templatedata-modal-table-param-suggestedvalues": "Label for a parameter property input: List of suggested values",
|
||||
"templatedata-modal-table-param-suggestedvalues-placeholder": "Placeholder text for suggested values field.",
|
||||
"templatedata-modal-table-param-type": "Label for a parameter property input: Type of the parameter.\n{{Identical|Type}}",
|
||||
"templatedata-modal-table-param-uneditablefield": "Placeholder text notifying the user the field is uneditable",
|
||||
"templatedata-modal-title": "Title of the edit dialog.",
|
||||
|
|
|
@ -42,6 +42,7 @@ class TemplateDataBlob {
|
|||
'default',
|
||||
'inherits',
|
||||
'type',
|
||||
'suggestedvalues',
|
||||
];
|
||||
|
||||
private const VALID_TYPES = [
|
||||
|
@ -367,6 +368,19 @@ class TemplateDataBlob {
|
|||
$paramObj->type = 'unknown';
|
||||
}
|
||||
|
||||
// Param.suggestedvalues
|
||||
if ( isset( $paramObj->suggestedvalues ) ) {
|
||||
if ( !is_array( $paramObj->suggestedvalues ) ) {
|
||||
return Status::newFatal(
|
||||
'templatedata-invalid-type',
|
||||
"params.{$paramName}.suggestedvalues",
|
||||
'array'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$paramObj->suggestedvalues = [];
|
||||
}
|
||||
|
||||
$paramNames[] = $paramName;
|
||||
}
|
||||
|
||||
|
@ -818,6 +832,20 @@ class TemplateDataBlob {
|
|||
}
|
||||
}
|
||||
|
||||
$suggestedValuesLine = '';
|
||||
if ( count( $paramObj->suggestedvalues ) ) {
|
||||
$suggestedValues = '';
|
||||
foreach ( $paramObj->suggestedvalues as $suggestedValue ) {
|
||||
$suggestedValues .= wfMessage( 'word-separator' )->inLanguage( $lang )->escaped()
|
||||
. Html::element( 'code', [
|
||||
'class' => 'mw-templatedata-doc-param-alias'
|
||||
], $suggestedValue );
|
||||
}
|
||||
$suggestedValuesLine .= Html::element( 'dt', [],
|
||||
wfMessage( 'templatedata-doc-param-suggestedvalues' )->inLanguage( $lang )->text()
|
||||
) . Html::rawElement( 'dd', [], $suggestedValues );
|
||||
}
|
||||
|
||||
$statusClass = '';
|
||||
if ( $paramObj->deprecated ) {
|
||||
$status = 'templatedata-doc-param-status-deprecated';
|
||||
|
@ -848,6 +876,8 @@ class TemplateDataBlob {
|
|||
wfMessage( 'templatedata-doc-param-desc-empty' )->inLanguage( $lang )->text()
|
||||
)
|
||||
. Html::rawElement( 'dl', [],
|
||||
// Suggested Values
|
||||
$suggestedValuesLine .
|
||||
// Default
|
||||
( $paramObj->default !== null ? ( Html::element( 'dt', [],
|
||||
wfMessage( 'templatedata-doc-param-default' )->inLanguage( $lang )->text()
|
||||
|
|
|
@ -158,6 +158,20 @@ class TemplateDataHooks {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Include config when appropriate.
|
||||
*
|
||||
* @param array &$vars
|
||||
* @param OutputPage $output
|
||||
* @see https://www.mediawiki.org/wiki/Manual:Hooks/MakeGlobalVariablesScript
|
||||
*/
|
||||
public static function onMakeGlobalVariablesScript( array &$vars, OutputPage $output ) {
|
||||
if ( $output->getTitle()->inNamespace( NS_TEMPLATE ) ) {
|
||||
$vars['wgTemplateDataSuggestedValuesEditor'] =
|
||||
$output->getConfig()->get( 'TemplateDataSuggestedValuesEditor' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parser hook for <templatedata>.
|
||||
* If there is any JSON provided, render the template documentation on the page.
|
||||
|
|
|
@ -162,6 +162,9 @@ Model.static.getAllProperties = function ( getFullData ) {
|
|||
],
|
||||
default: 'unknown'
|
||||
},
|
||||
suggestedvalues: {
|
||||
type: 'array'
|
||||
},
|
||||
default: {
|
||||
type: 'string',
|
||||
multiline: true,
|
||||
|
@ -1066,16 +1069,17 @@ Model.prototype.outputTemplateData = function () {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case 'suggestedvalues':
|
||||
case 'aliases':
|
||||
// Only update the aliases in if the new templatedata has an
|
||||
// aliases array that isn't empty
|
||||
// Only update these if the new templatedata has an
|
||||
// array that isn't empty
|
||||
if (
|
||||
Array.isArray( this.params[ key ][ prop ] ) &&
|
||||
this.params[ key ][ prop ].length > 0
|
||||
) {
|
||||
result.params[ name ][ prop ] = this.params[ key ][ prop ];
|
||||
} else {
|
||||
// If the new aliases array is empty, delete it from the original
|
||||
// If the new array is empty, delete it from the original
|
||||
delete result.params[ name ][ prop ];
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -891,6 +891,7 @@ Dialog.prototype.onParamPropertyInputChange = function ( property, value ) {
|
|||
|
||||
if ( property === 'type' ) {
|
||||
value = propInput.getMenu().findSelectedItem() ? propInput.getMenu().findSelectedItem().getData() : 'unknown';
|
||||
this.toggleSuggestedValues( value );
|
||||
}
|
||||
|
||||
if ( property === 'name' ) {
|
||||
|
@ -903,6 +904,10 @@ Dialog.prototype.onParamPropertyInputChange = function ( property, value ) {
|
|||
}
|
||||
}
|
||||
|
||||
if ( property === 'suggestedvalues' ) {
|
||||
value = propInput.getValue();
|
||||
}
|
||||
|
||||
if ( allProps[ property ].restrict ) {
|
||||
if ( value.match( allProps[ property ].restrict ) ) {
|
||||
// Error! Don't fix the model
|
||||
|
@ -946,6 +951,24 @@ Dialog.prototype.onParamPropertyInputChange = function ( property, value ) {
|
|||
this.trackPropertyChange( property );
|
||||
};
|
||||
|
||||
Dialog.prototype.toggleSuggestedValues = function ( type ) {
|
||||
var suggestedValuesAllowedTypes = [
|
||||
'content',
|
||||
'line',
|
||||
'number',
|
||||
'string',
|
||||
'unbalanced-wikitext',
|
||||
'unknown'
|
||||
];
|
||||
|
||||
// Don't show the suggested values field when the feature flag is
|
||||
// disabled, or for inapplicable types.
|
||||
this.propFieldLayout.suggestedvalues.toggle(
|
||||
mw.config.get( 'wgTemplateDataSuggestedValuesEditor' ) &&
|
||||
suggestedValuesAllowedTypes.indexOf( type ) !== -1
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the parameter details in the detail panel.
|
||||
*
|
||||
|
@ -966,6 +989,9 @@ Dialog.prototype.getParameterDetails = function ( paramKey ) {
|
|||
}
|
||||
}
|
||||
|
||||
// Update suggested values field visibility
|
||||
this.toggleSuggestedValues( paramData.type );
|
||||
|
||||
this.startParameterInputTracking( paramData );
|
||||
};
|
||||
|
||||
|
@ -1093,7 +1119,7 @@ Dialog.prototype.changeParamPropertyInput = function ( paramKey, propName, value
|
|||
if ( languageProps.indexOf( propName ) !== -1 ) {
|
||||
propInput.setValue( value[ lang ] );
|
||||
} else {
|
||||
if ( prop.type === 'array' && Array.isArray( value ) ) {
|
||||
if ( prop.type === 'array' && Array.isArray( value ) && prop.delimiter ) {
|
||||
value = value.join( prop.delimiter );
|
||||
}
|
||||
propInput.setValue( value );
|
||||
|
@ -1105,6 +1131,8 @@ Dialog.prototype.changeParamPropertyInput = function ( paramKey, propName, value
|
|||
propInput.selectItem( propInput.findItemFromData( prop.default ) );
|
||||
} else if ( prop.type === 'boolean' ) {
|
||||
propInput.setSelected( false );
|
||||
} else if ( propName === 'suggestedvalues' ) {
|
||||
propInput.setValue( [] );
|
||||
} else {
|
||||
propInput.setValue( '' );
|
||||
}
|
||||
|
@ -1178,6 +1206,11 @@ Dialog.prototype.createParamDetails = function () {
|
|||
case 'suggested':
|
||||
propInput = new OO.ui.CheckboxInputWidget( config );
|
||||
break;
|
||||
case 'suggestedvalues':
|
||||
config.allowArbitrary = true;
|
||||
config.placeholder = mw.msg( 'templatedata-modal-table-param-suggestedvalues-placeholder' );
|
||||
propInput = new OO.ui.TagMultiselectWidget( config );
|
||||
break;
|
||||
default:
|
||||
if ( config.multiline === true ) {
|
||||
delete config.multiline;
|
||||
|
@ -1206,6 +1239,7 @@ Dialog.prototype.createParamDetails = function () {
|
|||
// * tdg-templateDataDialog-paramInput tdg-templateDataDialog-paramList-name
|
||||
// * tdg-templateDataDialog-paramInput tdg-templateDataDialog-paramList-required
|
||||
// * tdg-templateDataDialog-paramInput tdg-templateDataDialog-paramList-suggested
|
||||
// * tdg-templateDataDialog-paramInput tdg-templateDataDialog-paramList-suggestedvalues
|
||||
// * tdg-templateDataDialog-paramInput tdg-templateDataDialog-paramList-type
|
||||
// * tdg-templateDataDialog-paramInput tdg-templateDataDialog-paramList-uneditablefield
|
||||
propInput.$element
|
||||
|
@ -1228,6 +1262,7 @@ Dialog.prototype.createParamDetails = function () {
|
|||
// * templatedata-modal-table-param-name
|
||||
// * templatedata-modal-table-param-required
|
||||
// * templatedata-modal-table-param-suggested
|
||||
// * templatedata-modal-table-param-suggestedvalues
|
||||
// * templatedata-modal-table-param-type
|
||||
// * templatedata-modal-table-param-uneditablefield
|
||||
label: mw.msg( 'templatedata-modal-table-param-' + property )
|
||||
|
@ -1276,6 +1311,7 @@ Dialog.prototype.updateParamDetailsLanguage = function ( lang ) {
|
|||
// * templatedata-modal-table-param-name
|
||||
// * templatedata-modal-table-param-required
|
||||
// * templatedata-modal-table-param-suggested
|
||||
// * templatedata-modal-table-param-suggestedvalues
|
||||
// * templatedata-modal-table-param-type
|
||||
// * templatedata-modal-table-param-uneditablefield
|
||||
label = mw.msg( 'templatedata-modal-table-param-' + prop, lang );
|
||||
|
|
|
@ -106,6 +106,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"example": null,
|
||||
"required": false,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"deprecated": false,
|
||||
"aliases": [],
|
||||
"type": "unknown",
|
||||
|
@ -139,6 +140,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"autovalue": null,
|
||||
"required": false,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"deprecated": false,
|
||||
"aliases": [],
|
||||
"type": "line"
|
||||
|
@ -185,6 +187,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"example": null,
|
||||
"required": false,
|
||||
"suggested": true,
|
||||
"suggestedvalues": [],
|
||||
"deprecated": false,
|
||||
"aliases": [
|
||||
"1"
|
||||
|
@ -229,6 +232,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"example": null,
|
||||
"required": true,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"default": {
|
||||
"en": "example"
|
||||
},
|
||||
|
@ -245,6 +249,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"example": null,
|
||||
"required": true,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"default": {
|
||||
"en": "overridden"
|
||||
},
|
||||
|
@ -333,6 +338,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"required": false,
|
||||
"example": null,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"description": null,
|
||||
"deprecated": false,
|
||||
"aliases": [],
|
||||
|
@ -344,6 +350,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"label": null,
|
||||
"required": false,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"description": null,
|
||||
"example": null,
|
||||
"deprecated": false,
|
||||
|
@ -356,6 +363,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"label": null,
|
||||
"required": false,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"description": null,
|
||||
"example": null,
|
||||
"deprecated": false,
|
||||
|
@ -396,6 +404,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"autovalue": "{{SomeTemplate}}",
|
||||
"required": true,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [ "baz", "boo" ],
|
||||
"deprecated": false,
|
||||
"aliases": [ "foo", "baz" ],
|
||||
"type": "line"
|
||||
|
@ -424,6 +433,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"autovalue": "{{SomeTemplate}}",
|
||||
"required": true,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [ "baz", "boo" ],
|
||||
"deprecated": false,
|
||||
"aliases": [ "foo", "baz" ],
|
||||
"type": "line"
|
||||
|
@ -893,6 +903,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"required": false,
|
||||
"example": null,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"description": null,
|
||||
"deprecated": false,
|
||||
"aliases": [],
|
||||
|
@ -928,6 +939,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"default": "French",
|
||||
"required": false,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"description": null,
|
||||
"deprecated": false,
|
||||
"aliases": [],
|
||||
|
@ -964,6 +976,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"label": null,
|
||||
"required": false,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"description": null,
|
||||
"example": null,
|
||||
"deprecated": false,
|
||||
|
@ -1004,6 +1017,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"label": null,
|
||||
"required": false,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"description": null,
|
||||
"example": null,
|
||||
"deprecated": false,
|
||||
|
@ -1080,6 +1094,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"label": null,
|
||||
"required": false,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"description": null,
|
||||
"example": null,
|
||||
"deprecated": false,
|
||||
|
@ -1092,6 +1107,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"label": null,
|
||||
"required": false,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"description": null,
|
||||
"example": null,
|
||||
"deprecated": false,
|
||||
|
@ -1104,6 +1120,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"label": null,
|
||||
"required": false,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"description": null,
|
||||
"example": null,
|
||||
"deprecated": false,
|
||||
|
@ -1137,6 +1154,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"label": null,
|
||||
"required": false,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"description": null,
|
||||
"example": null,
|
||||
"deprecated": false,
|
||||
|
@ -1149,6 +1167,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"label": null,
|
||||
"required": false,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"description": null,
|
||||
"example": null,
|
||||
"deprecated": false,
|
||||
|
@ -1161,6 +1180,7 @@ class TemplateDataBlobTest extends MediaWikiTestCase {
|
|||
"label": null,
|
||||
"required": false,
|
||||
"suggested": false,
|
||||
"suggestedvalues": [],
|
||||
"description": null,
|
||||
"example": null,
|
||||
"deprecated": false,
|
||||
|
|
|
@ -325,6 +325,7 @@ QUnit.test( 'Validation tools', function ( assert ) {
|
|||
'description',
|
||||
'example',
|
||||
'type',
|
||||
'suggestedvalues',
|
||||
'default',
|
||||
'autovalue',
|
||||
'deprecated',
|
||||
|
|
Loading…
Reference in a new issue