/** * InputWidget is the base class for all input widgets, which * include {@link OO.ui.TextInputWidget text inputs}, {@link OO.ui.CheckboxInputWidget checkbox inputs}, * {@link OO.ui.RadioInputWidget radio inputs}, and {@link OO.ui.ButtonInputWidget button inputs}. * See the [OOjs UI documentation on MediaWiki] [1] for more information and examples. * * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs * * @abstract * @class * @extends OO.ui.Widget * @mixins OO.ui.FlaggedElement * @mixins OO.ui.TabIndexedElement * * @constructor * @param {Object} [config] Configuration options * @cfg {string} [name=''] The value of the input’s HTML `name` attribute. * @cfg {string} [value=''] The value of the input. * @cfg {Function} [inputFilter] The name of an input filter function. Input filters modify the value of an input * before it is accepted. */ OO.ui.InputWidget = function OoUiInputWidget( config ) { // Configuration initialization config = config || {}; // Parent constructor OO.ui.InputWidget.super.call( this, config ); // Properties this.$input = this.getInputElement( config ); this.value = ''; this.inputFilter = config.inputFilter; // Mixin constructors OO.ui.FlaggedElement.call( this, config ); OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$input } ) ); // Events this.$input.on( 'keydown mouseup cut paste change input select', this.onEdit.bind( this ) ); // Initialization this.$input .attr( 'name', config.name ) .prop( 'disabled', this.isDisabled() ); this.$element.addClass( 'oo-ui-inputWidget' ).append( this.$input, $( '' ) ); this.setValue( config.value ); }; /* Setup */ OO.inheritClass( OO.ui.InputWidget, OO.ui.Widget ); OO.mixinClass( OO.ui.InputWidget, OO.ui.FlaggedElement ); OO.mixinClass( OO.ui.InputWidget, OO.ui.TabIndexedElement ); /* Events */ /** * @event change * * A change event is emitted when the value of the input changes. * * @param {string} value */ /* Methods */ /** * Get input element. * * Subclasses of OO.ui.InputWidget use the `config` parameter to produce different elements in * different circumstances. The element must have a `value` property (like form elements). * * @private * @param {Object} config Configuration options * @return {jQuery} Input element */ OO.ui.InputWidget.prototype.getInputElement = function () { return $( '' ); }; /** * Handle potentially value-changing events. * * @private * @param {jQuery.Event} e Key down, mouse up, cut, paste, change, input, or select event */ OO.ui.InputWidget.prototype.onEdit = function () { var widget = this; if ( !this.isDisabled() ) { // Allow the stack to clear so the value will be updated setTimeout( function () { widget.setValue( widget.$input.val() ); } ); } }; /** * Get the value of the input. * * @return {string} Input value */ OO.ui.InputWidget.prototype.getValue = function () { // Resynchronize our internal data with DOM data. Other scripts executing on the page can modify // it, and we won't know unless they're kind enough to trigger a 'change' event. var value = this.$input.val(); if ( this.value !== value ) { this.setValue( value ); } return this.value; }; /** * Set the direction of the input, either RTL (right-to-left) or LTR (left-to-right). * * @param {boolean} isRTL * Direction is right-to-left */ OO.ui.InputWidget.prototype.setRTL = function ( isRTL ) { this.$input.prop( 'dir', isRTL ? 'rtl' : 'ltr' ); }; /** * Set the value of the input. * * @param {string} value New value * @fires change * @chainable */ OO.ui.InputWidget.prototype.setValue = function ( value ) { value = this.cleanUpValue( value ); // Update the DOM if it has changed. Note that with cleanUpValue, it // is possible for the DOM value to change without this.value changing. if ( this.$input.val() !== value ) { this.$input.val( value ); } if ( this.value !== value ) { this.value = value; this.emit( 'change', this.value ); } return this; }; /** * Clean up incoming value. * * Ensures value is a string, and converts undefined and null to empty string. * * @private * @param {string} value Original value * @return {string} Cleaned up value */ OO.ui.InputWidget.prototype.cleanUpValue = function ( value ) { if ( value === undefined || value === null ) { return ''; } else if ( this.inputFilter ) { return this.inputFilter( String( value ) ); } else { return String( value ); } }; /** * Simulate the behavior of clicking on a label bound to this input. This method is only called by * {@link OO.ui.LabelWidget LabelWidget} and {@link OO.ui.FieldLayout FieldLayout}. It should not be * called directly. */ OO.ui.InputWidget.prototype.simulateLabelClick = function () { if ( !this.isDisabled() ) { if ( this.$input.is( ':checkbox, :radio' ) ) { this.$input.click(); } if ( this.$input.is( ':input' ) ) { this.$input[ 0 ].focus(); } } }; /** * @inheritdoc */ OO.ui.InputWidget.prototype.setDisabled = function ( state ) { OO.ui.InputWidget.super.prototype.setDisabled.call( this, state ); if ( this.$input ) { this.$input.prop( 'disabled', this.isDisabled() ); } return this; }; /** * Focus the input. * * @chainable */ OO.ui.InputWidget.prototype.focus = function () { this.$input[ 0 ].focus(); return this; }; /** * Blur the input. * * @chainable */ OO.ui.InputWidget.prototype.blur = function () { this.$input[ 0 ].blur(); return this; };