Create Expiry Widget with Date Time Selector
Special:Block needs a date time selector for easier selection of expiry. To accommodate this cleanly, a new Expiry Widget is created that handles this logic. Bug: T132220 Change-Id: I2853a2ca0ae6ccead3978f4bb50a77c2baa3a150
This commit is contained in:
parent
71a653a495
commit
3481e3b2e0
11 changed files with 520 additions and 19 deletions
|
|
@ -564,6 +564,7 @@ $wgAutoloadLocalClasses = [
|
|||
'HTMLComboboxField' => __DIR__ . '/includes/htmlform/fields/HTMLComboboxField.php',
|
||||
'HTMLDateTimeField' => __DIR__ . '/includes/htmlform/fields/HTMLDateTimeField.php',
|
||||
'HTMLEditTools' => __DIR__ . '/includes/htmlform/fields/HTMLEditTools.php',
|
||||
'HTMLExpiryField' => __DIR__ . '/includes/htmlform/fields/HTMLExpiryField.php',
|
||||
'HTMLFileCache' => __DIR__ . '/includes/cache/HTMLFileCache.php',
|
||||
'HTMLFloatField' => __DIR__ . '/includes/htmlform/fields/HTMLFloatField.php',
|
||||
'HTMLForm' => __DIR__ . '/includes/htmlform/HTMLForm.php',
|
||||
|
|
@ -992,6 +993,7 @@ $wgAutoloadLocalClasses = [
|
|||
'MediaWiki\\Widget\\ComplexTitleInputWidget' => __DIR__ . '/includes/widget/ComplexTitleInputWidget.php',
|
||||
'MediaWiki\\Widget\\DateInputWidget' => __DIR__ . '/includes/widget/DateInputWidget.php',
|
||||
'MediaWiki\\Widget\\DateTimeInputWidget' => __DIR__ . '/includes/widget/DateTimeInputWidget.php',
|
||||
'MediaWiki\\Widget\\ExpiryInputWidget' => __DIR__ . '/includes/widget/ExpiryInputWidget.php',
|
||||
'MediaWiki\\Widget\\NamespaceInputWidget' => __DIR__ . '/includes/widget/NamespaceInputWidget.php',
|
||||
'MediaWiki\\Widget\\SearchInputWidget' => __DIR__ . '/includes/widget/SearchInputWidget.php',
|
||||
'MediaWiki\\Widget\\Search\\BasicSearchResultSetWidget' => __DIR__ . '/includes/widget/search/BasicSearchResultSetWidget.php',
|
||||
|
|
|
|||
|
|
@ -8838,6 +8838,15 @@ $wgCommentTableSchemaMigrationStage = MIGRATION_OLD;
|
|||
*/
|
||||
$wgActorTableSchemaMigrationStage = MIGRATION_OLD;
|
||||
|
||||
/**
|
||||
* Temporary option to disable the date picker from the Expiry Widget.
|
||||
*
|
||||
* @since 1.32
|
||||
* @deprecated 1.32
|
||||
* @var bool
|
||||
*/
|
||||
$wgExpiryWidgetNoDatePicker = false;
|
||||
|
||||
/**
|
||||
* For really cool vim folding this needs to be at the end:
|
||||
* vim: foldmarker=@{,@} foldmethod=marker
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ class HTMLForm extends ContextSource {
|
|||
'date' => HTMLDateTimeField::class,
|
||||
'time' => HTMLDateTimeField::class,
|
||||
'datetime' => HTMLDateTimeField::class,
|
||||
'expiry' => HTMLExpiryField::class,
|
||||
// HTMLTextField will output the correct type="" attribute automagically.
|
||||
// There are about four zillion other HTML5 input types, like range, but
|
||||
// we don't use those at the moment, so no point in adding all of them.
|
||||
|
|
|
|||
88
includes/htmlform/fields/HTMLExpiryField.php
Normal file
88
includes/htmlform/fields/HTMLExpiryField.php
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
use MediaWiki\Widget\ExpiryInputWidget;
|
||||
|
||||
/**
|
||||
* Expiry Field that allows the user to specify a precise date or a
|
||||
* relative date string.
|
||||
*/
|
||||
class HTMLExpiryField extends HTMLFormField {
|
||||
|
||||
/**
|
||||
* @var HTMLFormField
|
||||
*/
|
||||
protected $relativeField;
|
||||
|
||||
/**
|
||||
* Relative Date Time Field.
|
||||
*/
|
||||
public function __construct( array $params = [] ) {
|
||||
parent::__construct( $params );
|
||||
|
||||
$type = !empty( $params['options'] ) ? 'selectorother' : 'text';
|
||||
$this->relativeField = $this->getFieldByType( $type );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Use whatever the relative field is as the standard HTML input.
|
||||
*/
|
||||
public function getInputHTML( $value ) {
|
||||
return $this->relativeField->getInputHtml( $value );
|
||||
}
|
||||
|
||||
protected function shouldInfuseOOUI() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getOOUIModules() {
|
||||
return array_merge(
|
||||
[
|
||||
'mediawiki.widgets.expiry',
|
||||
],
|
||||
$this->relativeField->getOOUIModules()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInputOOUI( $value ) {
|
||||
return new ExpiryInputWidget(
|
||||
$this->relativeField->getInputOOUI( $value ),
|
||||
[
|
||||
'id' => $this->mID,
|
||||
'required' => isset( $this->mParams['required'] ) ? $this->mParams['required'] : false,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadDataFromRequest( $request ) {
|
||||
return $this->relativeField->loadDataFromRequest( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTMLForm field by the type string.
|
||||
*
|
||||
* @param string $type
|
||||
* @return \HTMLFormField
|
||||
*/
|
||||
protected function getFieldByType( $type ) {
|
||||
$class = HTMLForm::$typeMappings[$type];
|
||||
$params = $this->mParams;
|
||||
$params['type'] = $type;
|
||||
$params['class'] = $class;
|
||||
|
||||
// Remove Parameters that are being used on the parent.
|
||||
unset( $params['label-message'] );
|
||||
return new $class( $params );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -151,11 +151,10 @@ class SpecialBlock extends FormSpecialPage {
|
|||
'validation-callback' => [ __CLASS__, 'validateTargetField' ],
|
||||
],
|
||||
'Expiry' => [
|
||||
'type' => !count( $suggestedDurations ) ? 'text' : 'selectorother',
|
||||
'type' => 'expiry',
|
||||
'label-message' => 'ipbexpiry',
|
||||
'required' => true,
|
||||
'options' => $suggestedDurations,
|
||||
'other' => $this->msg( 'ipbother' )->text(),
|
||||
'default' => $this->msg( 'ipb-default-expiry' )->inContentLanguage()->text(),
|
||||
],
|
||||
'Reason' => [
|
||||
|
|
@ -876,29 +875,38 @@ class SpecialBlock extends FormSpecialPage {
|
|||
$a[$show] = $value;
|
||||
}
|
||||
|
||||
if ( $a ) {
|
||||
// if options exist, add other to the end instead of the begining (which
|
||||
// is what happens by default).
|
||||
$a[ wfMessage( 'ipbother' )->text() ] = 'other';
|
||||
}
|
||||
|
||||
return $a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a submitted expiry time, which may be relative ("2 weeks", etc) or absolute
|
||||
* ("24 May 2034", etc), into an absolute timestamp we can put into the database.
|
||||
*
|
||||
* @todo strtotime() only accepts English strings. This means the expiry input
|
||||
* can only be specified in English.
|
||||
* @see https://secure.php.net/manual/en/function.strtotime.php
|
||||
*
|
||||
* @param string $expiry Whatever was typed into the form
|
||||
* @return string Timestamp or 'infinity'
|
||||
* @return string|bool Timestamp or 'infinity' or false on error.
|
||||
*/
|
||||
public static function parseExpiryInput( $expiry ) {
|
||||
if ( wfIsInfinity( $expiry ) ) {
|
||||
$expiry = 'infinity';
|
||||
} else {
|
||||
$expiry = strtotime( $expiry );
|
||||
|
||||
if ( $expiry < 0 || $expiry === false ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$expiry = wfTimestamp( TS_MW, $expiry );
|
||||
return 'infinity';
|
||||
}
|
||||
|
||||
return $expiry;
|
||||
$expiry = strtotime( $expiry );
|
||||
|
||||
if ( $expiry < 0 || $expiry === false ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return wfTimestamp( TS_MW, $expiry );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
77
includes/widget/ExpiryInputWidget.php
Normal file
77
includes/widget/ExpiryInputWidget.php
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace MediaWiki\Widget;
|
||||
|
||||
use OOUI\Widget;
|
||||
|
||||
/**
|
||||
* Expiry widget.
|
||||
*
|
||||
* Allows the user to toggle between a precise time or enter a relative time,
|
||||
* regardless, the value comes in as a relative time.
|
||||
*
|
||||
* @copyright 2018 MediaWiki Widgets Team and others; see AUTHORS.txt
|
||||
* @license MIT
|
||||
*/
|
||||
class ExpiryInputWidget extends Widget {
|
||||
|
||||
/**
|
||||
* @var Widget
|
||||
*/
|
||||
protected $relativeInput;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $noDatePicker;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $required;
|
||||
|
||||
/**
|
||||
* @param Widget $relativeInput
|
||||
* @param array $options Configuration options
|
||||
*/
|
||||
public function __construct( Widget $relativeInput, array $options = [] ) {
|
||||
$config = \RequestContext::getMain()->getConfig();
|
||||
|
||||
$options['noDatePicker'] = $config->get( 'ExpiryWidgetNoDatePicker' );
|
||||
|
||||
parent::__construct( $options );
|
||||
|
||||
$this->noDatePicker = $options['noDatePicker'];
|
||||
$this->required = isset( $options['required'] ) ? $options['required'] : false;
|
||||
|
||||
// Properties
|
||||
$this->relativeInput = $relativeInput;
|
||||
$this->relativeInput->addClasses( [ 'mw-widget-ExpiryWidget-relative' ] );
|
||||
|
||||
// Initialization
|
||||
$classes = [
|
||||
'mw-widget-ExpiryWidget',
|
||||
];
|
||||
if ( $options['noDatePicker'] === false ) {
|
||||
$classes[] = 'mw-widget-ExpiryWidget-hasDatePicker';
|
||||
}
|
||||
$this
|
||||
->addClasses( $classes )
|
||||
->appendContent( $this->relativeInput );
|
||||
}
|
||||
|
||||
protected function getJavaScriptClassName() {
|
||||
return 'mw.widgets.ExpiryWidget';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfig( &$config ) {
|
||||
$config['noDatePicker'] = $this->noDatePicker;
|
||||
$config['required'] = $this->required;
|
||||
$config['relativeInput'] = [];
|
||||
$this->relativeInput->getConfig( $config['relativeInput'] );
|
||||
return parent::getConfig( $config );
|
||||
}
|
||||
}
|
||||
|
|
@ -2063,9 +2063,13 @@ return [
|
|||
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.block.js',
|
||||
'dependencies' => [
|
||||
'oojs-ui-core',
|
||||
'oojs-ui.styles.icons-editing-core',
|
||||
'oojs-ui.styles.icons-editing-advanced',
|
||||
'mediawiki.widgets.SelectWithInputWidget',
|
||||
'mediawiki.widgets.DateInputWidget',
|
||||
'mediawiki.util',
|
||||
'mediawiki.htmlform',
|
||||
'moment',
|
||||
],
|
||||
],
|
||||
'mediawiki.special.changecredentials.js' => [
|
||||
|
|
@ -2604,6 +2608,21 @@ return [
|
|||
],
|
||||
'targets' => [ 'desktop', 'mobile' ],
|
||||
],
|
||||
'mediawiki.widgets.expiry' => [
|
||||
'scripts' => [
|
||||
'resources/src/mediawiki.widgets/mw.widgets.ExpiryInputWidget.js',
|
||||
],
|
||||
'dependencies' => [
|
||||
'oojs-ui-core',
|
||||
'oojs-ui-widgets',
|
||||
'moment',
|
||||
'mediawiki.widgets.datetime'
|
||||
],
|
||||
'skinStyles' => [
|
||||
'default' => 'resources/src/mediawiki.widgets/mw.widgets.ExpiryInputWidget.less',
|
||||
],
|
||||
'targets' => [ 'desktop', 'mobile' ],
|
||||
],
|
||||
'mediawiki.widgets.CategoryMultiselectWidget' => [
|
||||
'scripts' => [
|
||||
'resources/src/mediawiki.widgets/mw.widgets.CategoryCapsuleItemWidget.js',
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
enableAutoblockField = infuseOrNull( $( '#mw-input-wpAutoBlock' ).closest( '.oo-ui-fieldLayout' ) ),
|
||||
hideUserField = infuseOrNull( $( '#mw-input-wpHideUser' ).closest( '.oo-ui-fieldLayout' ) ),
|
||||
watchUserField = infuseOrNull( $( '#mw-input-wpWatch' ).closest( '.oo-ui-fieldLayout' ) ),
|
||||
// mw.widgets.SelectWithInputWidget
|
||||
expiryWidget = infuseOrNull( 'mw-input-wpExpiry' );
|
||||
|
||||
function updateBlockOptions() {
|
||||
|
|
@ -28,11 +27,10 @@
|
|||
isIp = mw.util.isIPAddress( blocktarget, true ),
|
||||
isIpRange = isIp && blocktarget.match( /\/\d+$/ ),
|
||||
isNonEmptyIp = isIp && !isEmpty,
|
||||
expiryValue = expiryWidget.dropdowninput.getValue(),
|
||||
expiryValue = expiryWidget.getValue(),
|
||||
// infinityValues are the values the SpecialBlock class accepts as infinity (sf. wfIsInfinity)
|
||||
infinityValues = [ 'infinite', 'indefinite', 'infinity', 'never' ],
|
||||
isIndefinite = infinityValues.indexOf( expiryValue ) !== -1 ||
|
||||
( expiryValue === 'other' && infinityValues.indexOf( expiryWidget.textinput.getValue() ) !== -1 );
|
||||
isIndefinite = infinityValues.indexOf( expiryValue ) !== -1;
|
||||
|
||||
if ( enableAutoblockField ) {
|
||||
enableAutoblockField.toggle( !( isNonEmptyIp ) );
|
||||
|
|
@ -51,8 +49,7 @@
|
|||
if ( blockTargetWidget ) {
|
||||
// Bind functions so they're checked whenever stuff changes
|
||||
blockTargetWidget.on( 'change', updateBlockOptions );
|
||||
expiryWidget.dropdowninput.on( 'change', updateBlockOptions );
|
||||
expiryWidget.textinput.on( 'change', updateBlockOptions );
|
||||
expiryWidget.on( 'change', updateBlockOptions );
|
||||
|
||||
// Call them now to set initial state (ie. Special:Block/Foobar?wpBlockExpiry=2+hours)
|
||||
updateBlockOptions();
|
||||
|
|
|
|||
227
resources/src/mediawiki.widgets/mw.widgets.ExpiryInputWidget.js
Normal file
227
resources/src/mediawiki.widgets/mw.widgets.ExpiryInputWidget.js
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
/*!
|
||||
* MediaWiki Widgets - ExpiryWidget class.
|
||||
*
|
||||
* @copyright 2018 MediaWiki Widgets Team and others; see AUTHORS.txt
|
||||
* @license The MIT License (MIT); see LICENSE.txt
|
||||
*/
|
||||
/* global moment */
|
||||
( function ( $, mw ) {
|
||||
|
||||
/**
|
||||
* Creates a mw.widgets.ExpiryWidget object.
|
||||
*
|
||||
* @class mw.widgets.ExpiryWidget
|
||||
* @extends OO.ui.Widget
|
||||
*
|
||||
* @constructor
|
||||
* @param {Object} [config] Configuration options
|
||||
*/
|
||||
mw.widgets.ExpiryWidget = function ( config ) {
|
||||
var RFC2822 = 'ddd, DD MMM YYYY HH:mm:ss [GMT]';
|
||||
|
||||
// Config initialization
|
||||
config = $.extend( {}, config );
|
||||
|
||||
this.relativeField = new config.RelativeInputClass( config.relativeInput );
|
||||
this.relativeField.$element.addClass( 'mw-widget-ExpiryWidget-relative' );
|
||||
|
||||
// Parent constructor
|
||||
mw.widgets.ExpiryWidget.parent.call( this, config );
|
||||
|
||||
// If the wiki does not want the date picker, then initialize the relative
|
||||
// field and exit.
|
||||
if ( config.noDatePicker ) {
|
||||
this.relativeField.on( 'change', function ( event ) {
|
||||
// Emit a change event for this widget.
|
||||
this.emit( 'change', event );
|
||||
}.bind( this ) );
|
||||
|
||||
// Initialization
|
||||
this.$element
|
||||
.addClass( 'mw-widget-ExpiryWidget' )
|
||||
.append(
|
||||
this.relativeField.$element
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Properties
|
||||
this.inputSwitch = new OO.ui.ButtonSelectWidget( {
|
||||
tabIndex: -1,
|
||||
items: [
|
||||
new OO.ui.ButtonOptionWidget( {
|
||||
data: 'relative',
|
||||
icon: 'edit'
|
||||
} ),
|
||||
new OO.ui.ButtonOptionWidget( {
|
||||
data: 'date',
|
||||
icon: 'calendar'
|
||||
} )
|
||||
]
|
||||
} );
|
||||
this.dateTimeField = new mw.widgets.datetime.DateTimeInputWidget( {
|
||||
min: new Date(), // The selected date must at least be now.
|
||||
required: config.required
|
||||
} );
|
||||
|
||||
// Initially hide the dateTime field.
|
||||
this.dateTimeField.toggle( false );
|
||||
// Initially set the relative input.
|
||||
this.inputSwitch.selectItemByData( 'relative' );
|
||||
|
||||
// Events
|
||||
|
||||
// Toggle the visible inputs.
|
||||
this.inputSwitch.on( 'choose', function ( event ) {
|
||||
switch ( event.getData() ) {
|
||||
case 'date':
|
||||
this.dateTimeField.toggle( true );
|
||||
this.relativeField.toggle( false );
|
||||
break;
|
||||
case 'relative':
|
||||
this.dateTimeField.toggle( false );
|
||||
this.relativeField.toggle( true );
|
||||
break;
|
||||
}
|
||||
}.bind( this ) );
|
||||
|
||||
// When the date time field update, update the relative
|
||||
// field.
|
||||
this.dateTimeField.on( 'change', function ( value ) {
|
||||
var datetime;
|
||||
|
||||
// Do not alter the visible input.
|
||||
if ( this.relativeField.isVisible() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the value was cleared, do not attempt to parse it.
|
||||
if ( !value ) {
|
||||
this.relativeField.setValue( value );
|
||||
return;
|
||||
}
|
||||
|
||||
datetime = moment( value );
|
||||
|
||||
// If the datetime is invlaid for some reason, reset the relative field.
|
||||
if ( !datetime.isValid() ) {
|
||||
this.relativeField.setValue( undefined );
|
||||
}
|
||||
|
||||
// Set the relative field value. The field only accepts English strings.
|
||||
this.relativeField.setValue( datetime.utc().locale( 'en' ).format( RFC2822 ) );
|
||||
}.bind( this ) );
|
||||
|
||||
// When the relative field update, update the date time field if it's a
|
||||
// value that moment understands.
|
||||
this.relativeField.on( 'change', function ( event ) {
|
||||
var datetime;
|
||||
|
||||
// Emit a change event for this widget.
|
||||
this.emit( 'change', event );
|
||||
|
||||
// Do not alter the visible input.
|
||||
if ( this.dateTimeField.isVisible() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parsing of free text field may fail, so always check if the date is
|
||||
// valid.
|
||||
datetime = moment( event );
|
||||
|
||||
if ( datetime.isValid() ) {
|
||||
this.dateTimeField.setValue( datetime.utc().toISOString() );
|
||||
} else {
|
||||
this.dateTimeField.setValue( undefined );
|
||||
}
|
||||
}.bind( this ) );
|
||||
|
||||
// Initialization
|
||||
this.$element
|
||||
.addClass( 'mw-widget-ExpiryWidget' )
|
||||
.addClass( 'mw-widget-ExpiryWidget-hasDatePicker' )
|
||||
.append(
|
||||
this.inputSwitch.$element,
|
||||
this.dateTimeField.$element,
|
||||
this.relativeField.$element
|
||||
);
|
||||
|
||||
// Trigger an initial onChange.
|
||||
this.relativeField.emit( 'change', this.relativeField.getValue() );
|
||||
};
|
||||
|
||||
/* Inheritance */
|
||||
|
||||
OO.inheritClass( mw.widgets.ExpiryWidget, OO.ui.Widget );
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
mw.widgets.ExpiryWidget.static.reusePreInfuseDOM = function ( node, config ) {
|
||||
var relativeElement = $( node ).find( '.mw-widget-ExpiryWidget-relative' );
|
||||
|
||||
config = mw.widgets.ExpiryWidget.parent.static.reusePreInfuseDOM( node, config );
|
||||
|
||||
if ( relativeElement.hasClass( 'oo-ui-textInputWidget' ) ) {
|
||||
config.RelativeInputClass = OO.ui.TextInputWidget;
|
||||
} else if ( relativeElement.hasClass( 'mw-widget-selectWithInputWidget' ) ) {
|
||||
config.RelativeInputClass = mw.widgets.SelectWithInputWidget;
|
||||
}
|
||||
|
||||
config.relativeInput = config.RelativeInputClass.static.reusePreInfuseDOM(
|
||||
relativeElement,
|
||||
config.relativeInput
|
||||
);
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
mw.widgets.ExpiryWidget.static.gatherPreInfuseState = function ( node, config ) {
|
||||
var state = mw.widgets.ExpiryWidget.parent.static.gatherPreInfuseState( node, config );
|
||||
|
||||
state.relativeInput = config.RelativeInputClass.static.gatherPreInfuseState(
|
||||
$( node ).find( '.mw-widget-ExpiryWidget-relative' ),
|
||||
config.relativeInput
|
||||
);
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
mw.widgets.ExpiryWidget.prototype.restorePreInfuseState = function ( state ) {
|
||||
mw.widgets.ExpiryWidget.parent.prototype.restorePreInfuseState.call( this, state );
|
||||
this.relativeField.restorePreInfuseState( state.relativeInput );
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
mw.widgets.ExpiryWidget.prototype.setDisabled = function ( disabled ) {
|
||||
mw.widgets.ExpiryWidget.parent.prototype.setDisabled.call( this, disabled );
|
||||
this.relativeField.setDisabled( disabled );
|
||||
|
||||
if ( this.inputSwitch ) {
|
||||
this.inputSwitch.setDisabled( disabled );
|
||||
}
|
||||
|
||||
if ( this.dateTimeField ) {
|
||||
this.dateTimeField.setDisabled( disabled );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the value of the widget.
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
mw.widgets.ExpiryWidget.prototype.getValue = function () {
|
||||
return this.relativeField.getValue();
|
||||
};
|
||||
|
||||
}( jQuery, mediaWiki ) );
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
@wm-expirywidget-text-width: 43.3em;
|
||||
|
||||
.mw-widget-ExpiryWidget.mw-widget-ExpiryWidget-hasDatePicker {
|
||||
.oo-ui-buttonSelectWidget {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.oo-ui-textInputWidget.mw-widget-ExpiryWidget-relative {
|
||||
display: inline-block;
|
||||
max-width: @wm-expirywidget-text-width;
|
||||
}
|
||||
|
||||
.mw-widget-selectWithInputWidget.mw-widget-ExpiryWidget-relative .oo-ui-textInputWidget {
|
||||
max-width: 22.8em;
|
||||
}
|
||||
|
||||
.mw-widgets-datetime-dateTimeInputWidget {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
max-width: @wm-expirywidget-text-width;
|
||||
|
||||
.mw-widgets-datetime-dateTimeInputWidget-handle {
|
||||
max-height: 2.286em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,6 +50,9 @@
|
|||
|
||||
// Events
|
||||
this.dropdowninput.on( 'change', this.onChange.bind( this ) );
|
||||
this.textinput.on( 'change', function () {
|
||||
this.emit( 'change', this.getValue() );
|
||||
}.bind( this ) );
|
||||
|
||||
// Parent constructor
|
||||
mw.widgets.SelectWithInputWidget.parent.call( this, config );
|
||||
|
|
@ -125,6 +128,48 @@
|
|||
this.textinput.setDisabled( textinputIsHidden || disabled );
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the value from outside.
|
||||
*
|
||||
* @param {string|undefined} value
|
||||
*/
|
||||
mw.widgets.SelectWithInputWidget.prototype.setValue = function ( value ) {
|
||||
var selectable = false;
|
||||
|
||||
if ( this.or ) {
|
||||
if ( value !== 'other' ) {
|
||||
selectable = !!this.dropdowninput.dropdownWidget.getMenu().findItemFromData( value );
|
||||
}
|
||||
|
||||
if ( selectable ) {
|
||||
this.dropdowninput.setValue( value );
|
||||
this.textinput.setValue( undefined );
|
||||
} else {
|
||||
this.dropdowninput.setValue( 'other' );
|
||||
this.textinput.setValue( value );
|
||||
}
|
||||
|
||||
this.emit( 'change', value );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the value from outside.
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
mw.widgets.SelectWithInputWidget.prototype.getValue = function () {
|
||||
if ( this.or ) {
|
||||
if ( this.dropdowninput.getValue() !== 'other' ) {
|
||||
return this.dropdowninput.getValue();
|
||||
}
|
||||
|
||||
return this.textinput.getValue();
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle change events on the DropdownInput
|
||||
*
|
||||
|
|
@ -140,6 +185,8 @@
|
|||
// submitted with the form. So we should also disable fields when hiding them.
|
||||
this.textinput.setDisabled( value !== 'other' || this.isDisabled() );
|
||||
}
|
||||
|
||||
this.emit( 'change', this.getValue() );
|
||||
};
|
||||
|
||||
}( jQuery, mediaWiki ) );
|
||||
|
|
|
|||
Loading…
Reference in a new issue