Localisation updates from https://translatewiki.net.
[mediawiki.git] / resources / src / mediawiki.widgets / Table / mw.widgets.RowWidget.js
blobe216943bc8af307107c3700a81d2b8d1faf52cba
1 /**
2  * @classdesc Table row widget. A RowWidget is used in conjunction with
3  * {@link mw.widgets.TableWidget table widgets} and should not be instantiated by themselves.
4  * They group together {@link OO.ui.TextInputWidget text input widgets} to form a unified row of
5  * editable data.
6  *
7  * @class
8  * @extends OO.ui.Widget
9  * @mixes OO.ui.mixin.GroupElement
10  *
11  * @constructor
12  * @description Create an instance of `mw.widgets.RowWidget`.
13  * @param {Object} [config] Configuration options
14  * @param {Array} [config.data] The data of the cells
15  * @param {Array} [config.keys] An array of keys for easy cell selection
16  * @param {RegExp|Function|string} [config.validate] Validation pattern to apply on every cell
17  * @param {number} [config.index] The row index.
18  * @param {string} [config.label] The row label to display. If not provided, the row index will
19  * be used be default. If set to null, no label will be displayed.
20  * @param {boolean} [config.showLabel=true] Show row label. Defaults to true.
21  * @param {boolean} [config.deletable=true] Whether the table should provide deletion UI tools
22  * for this row or not. Defaults to true.
23  */
24 mw.widgets.RowWidget = function MwWidgetsRowWidget( config ) {
25         config = config || {};
27         // Parent constructor
28         mw.widgets.RowWidget.super.call( this, config );
30         // Mixin constructor
31         OO.ui.mixin.GroupElement.call( this, config );
33         // Set up model
34         this.model = new mw.widgets.RowWidgetModel( config );
36         // Set up group element
37         this.setGroupElement(
38                 $( '<div>' )
39                         .addClass( 'mw-widgets-rowWidget-cells' )
40         );
42         // Set up label
43         this.labelCell = new OO.ui.LabelWidget( {
44                 classes: [ 'mw-widgets-rowWidget-label' ]
45         } );
47         // Set up delete button
48         if ( this.model.getRowProperties().isDeletable ) {
49                 this.deleteButton = new OO.ui.ButtonWidget( {
50                         icon: 'trash',
51                         classes: [ 'mw-widgets-rowWidget-delete-button' ],
52                         flags: 'destructive',
53                         title: mw.msg( 'mw-widgets-table-row-delete' )
54                 } );
55         }
57         // Events
58         this.model.connect( this, {
59                 valueChange: 'onValueChange',
60                 insertCell: 'onInsertCell',
61                 removeCell: 'onRemoveCell',
62                 clear: 'onClear',
63                 labelUpdate: 'onLabelUpdate'
64         } );
66         this.aggregate( {
67                 change: 'cellChange'
68         } );
70         this.connect( this, {
71                 cellChange: 'onCellChange'
72         } );
74         if ( this.model.getRowProperties().isDeletable ) {
75                 this.deleteButton.connect( this, {
76                         click: 'onDeleteButtonClick'
77                 } );
78         }
80         // Initialization
81         this.$element.addClass( 'mw-widgets-rowWidget' );
83         this.$element.append(
84                 this.labelCell.$element,
85                 this.$group
86         );
88         if ( this.model.getRowProperties().isDeletable ) {
89                 this.$element.append( this.deleteButton.$element );
90         }
92         this.setLabel( this.model.getRowProperties().label );
94         this.model.setupRow();
97 /* Inheritance */
99 OO.inheritClass( mw.widgets.RowWidget, OO.ui.Widget );
100 OO.mixinClass( mw.widgets.RowWidget, OO.ui.mixin.GroupElement );
102 /* Events */
105  * Change when an input contained within the row is updated.
107  * @event mw.widgets.RowWidget.inputChange
108  * @param {number} index The index of the cell that changed
109  * @param {string} value The new value of the cell
110  */
113  * Fired when the delete button for the row is pressed.
115  * @event mw.widgets.RowWidget.deleteButtonClick
116  */
118 /* Methods */
121  * @private
122  * @inheritdoc
123  */
124 mw.widgets.RowWidget.prototype.addItems = function ( items, index ) {
125         let i, len;
127         OO.ui.mixin.GroupElement.prototype.addItems.call( this, items, index );
129         for ( i = index, len = items.length; i < len; i++ ) {
130                 items[ i ].setData( i );
131         }
135  * @private
136  * @inheritdoc
137  */
138 mw.widgets.RowWidget.prototype.removeItems = function ( items ) {
139         OO.ui.mixin.GroupElement.prototype.removeItems.call( this, items );
141         const cells = this.getItems();
142         for ( let i = 0, len = cells.length; i < len; i++ ) {
143                 cells[ i ].setData( i );
144         }
148  * Get the row index.
150  * @return {number} The row index
151  */
152 mw.widgets.RowWidget.prototype.getIndex = function () {
153         return this.model.getRowProperties().index;
157  * Set the row index.
159  * @param {number} index The new index
160  */
161 mw.widgets.RowWidget.prototype.setIndex = function ( index ) {
162         this.model.setIndex( index );
166  * Get the label displayed on the row. If no custom label is set, the
167  * row index is used instead.
169  * @return {string} The row label
170  */
171 mw.widgets.RowWidget.prototype.getLabel = function () {
172         const props = this.model.getRowProperties();
174         if ( props.label === null ) {
175                 return '';
176         } else if ( !props.label ) {
177                 return props.index.toString();
178         } else {
179                 return props.label;
180         }
184  * @event mw.widgets.RowWidget.labelUpdate
185  * @param {string} label
186  */
189  * Set the label to be displayed on the widget.
191  * @param {string} label The new label
192  * @fires mw.widgets.RowWidget.labelUpdate
193  */
194 mw.widgets.RowWidget.prototype.setLabel = function ( label ) {
195         this.model.setLabel( label );
199  * Set the value of a particular cell.
201  * @param {number} index The cell index
202  * @param {string} value The new value
203  */
204 mw.widgets.RowWidget.prototype.setValue = function ( index, value ) {
205         this.model.setValue( index, value );
209  * Insert a cell at a specified index.
211  * @param  {string} data The cell data
212  * @param  {number} index The index to insert the cell at
213  * @param  {string} key A key for easy cell selection
214  */
215 mw.widgets.RowWidget.prototype.insertCell = function ( data, index, key ) {
216         this.model.insertCell( data, index, key );
220  * Removes a column at a specified index.
222  * @param {number} index The index to removeColumn
223  */
224 mw.widgets.RowWidget.prototype.removeCell = function ( index ) {
225         this.model.removeCell( index );
229  * Clear the field values.
230  */
231 mw.widgets.RowWidget.prototype.clear = function () {
232         this.model.clear();
236  * Handle model value changes.
238  * @param {number} index The column index of the updated cell
239  * @param {number} value The new value
241  * @fires mw.widgets.RowWidget.inputChange
242  */
243 mw.widgets.RowWidget.prototype.onValueChange = function ( index, value ) {
244         this.getItems()[ index ].setValue( value );
245         this.emit( 'inputChange', index, value );
249  * Handle model cell insertions.
251  * @param {string} data The initial data
252  * @param {number} index The index in which to insert the new cell
253  */
254 mw.widgets.RowWidget.prototype.onInsertCell = function ( data, index ) {
255         this.addItems( [
256                 new OO.ui.TextInputWidget( {
257                         data: index,
258                         value: data,
259                         validate: this.model.getValidationPattern()
260                 } )
261         ], index );
265  * Handle model cell removals.
267  * @param {number} index The removed cell index
268  */
269 mw.widgets.RowWidget.prototype.onRemoveCell = function ( index ) {
270         this.removeItems( [ index ] );
274  * Handle clear requests.
275  */
276 mw.widgets.RowWidget.prototype.onClear = function () {
277         const cells = this.getItems();
279         for ( let i = 0, len = cells.length; i < len; i++ ) {
280                 cells[ i ].setValue( '' );
281         }
285  * Update model label changes.
286  */
287 mw.widgets.RowWidget.prototype.onLabelUpdate = function () {
288         this.labelCell.setLabel( this.getLabel() );
292  * React to cell input change.
294  * @private
295  * @param {OO.ui.TextInputWidget} input The input that fired the event
296  * @param {string} value The value of the input
297  */
298 mw.widgets.RowWidget.prototype.onCellChange = function ( input, value ) {
299         // FIXME: The table itself should know if it contains invalid data
300         // in order to pass form state to the dialog when it asks if the Apply
301         // button should be enabled or not. This probably requires the table
302         // and each individual row to handle validation through an array of promises
303         // fed from the cells within.
304         // Right now, the table can't know if it's valid or not because the events
305         // don't get passed through.
306         input.getValidity().done( () => {
307                 this.model.setValue( input.getData(), value );
308         } );
312  * Handle delete button clicks.
314  * @private
315  * @fires mw.widgets.RowWidget.deleteButtonClick
316  */
317 mw.widgets.RowWidget.prototype.onDeleteButtonClick = function () {
318         this.emit( 'deleteButtonClick' );
322  * @inheritdoc
323  */
324 mw.widgets.RowWidget.prototype.setDisabled = function ( disabled ) {
325         // Parent method
326         mw.widgets.RowWidget.super.prototype.setDisabled.call( this, disabled );
328         if ( !this.items ) {
329                 return;
330         }
332         if ( this.model.getRowProperties().isDeletable ) {
333                 this.deleteButton.setDisabled( disabled );
334         }
336         this.getItems().forEach( ( cell ) => {
337                 cell.setDisabled( disabled );
338         } );