'ObjectFileCache' => __DIR__ . '/includes/cache/ObjectFileCache.php',
'OldChangesList' => __DIR__ . '/includes/changes/OldChangesList.php',
'OldLocalFile' => __DIR__ . '/includes/filerepo/file/OldLocalFile.php',
+ 'OOUIHTMLForm' => __DIR__ . '/includes/htmlform/OOUIHTMLForm.php',
'OracleInstaller' => __DIR__ . '/includes/installer/OracleInstaller.php',
'OracleUpdater' => __DIR__ . '/includes/installer/OracleUpdater.php',
'OrphanStats' => __DIR__ . '/maintenance/storage/orphanStats.php',
return true;
}
- function getAttributes( array $list ) {
+ // FIXME Ewww, this shouldn't be adding any attributes not requested in $list :(
+ public function getAttributes( array $list, array $mappings = null ) {
$attribs = array(
'type' => 'text',
'data-autocomplete' => FormatJson::encode( array_keys( $this->autocomplete ) ),
- ) + parent::getAttributes( $list );
+ ) + parent::getAttributes( $list, $mappings );
if ( $this->getOptions() ) {
$attribs['data-hide-if'] = FormatJson::encode(
return $ret;
}
+ /**
+ * Get the OOUI version of this input.
+ * @param string $value
+ * @return false
+ */
+ function getInputOOUI( $value ) {
+ // To be implemented, for now override the function from HTMLTextField
+ return false;
+ }
}
return Html::input( $this->mName, $value, $this->buttonType, $attr );
}
+ /**
+ * Get the OOUI widget for this field.
+ * @param string $value
+ * @return OOUI\ButtonInputWidget
+ */
+ public function getInputOOUI( $value ) {
+ return new OOUI\ButtonInputWidget( array(
+ 'name' => $this->mName,
+ 'value' => $value,
+ 'type' => $this->buttonType,
+ 'classes' => array( 'mw-htmlform-submit', $this->mClass ),
+ 'id' => $this->mID,
+ ) + $this->getAttributes( array( 'disabled', 'tabindex' ), array( 'tabindex' => 'tabIndex' ) ) );
+ }
+
protected function needsLabel() {
return false;
}
return $chkLabel;
}
+ /**
+ * Get the OOUI version of this field.
+ * @since 1.26
+ * @param string $value
+ * @return OOUI\CheckboxInputWidget The checkbox widget.
+ */
+ public function getInputOOUI( $value ) {
+ if ( !empty( $this->mParams['invert'] ) ) {
+ $value = !$value;
+ }
+
+ $attr = $this->getTooltipAndAccessKey();
+ $attr['id'] = $this->mID;
+ $attr['name'] = $this->mName;
+
+ $attr += $this->getAttributes( array( 'disabled', 'tabindex' ), array( 'tabindex' => 'tabIndex' ) );
+
+ if ( $this->mClass !== '' ) {
+ $attr['classes'] = array( $this->mClass );
+ }
+
+ $attr['selected'] = $value;
+ $attr['value'] = '1'; // Nasty hack, but needed to make this work
+
+ return new OOUI\CheckboxInputWidget( $attr );
+ }
+
/**
* For a checkbox, the label goes on the right hand side, and is
* added in getInputHTML(), rather than HTMLFormField::getRow()
+ *
+ * ...unless OOUI is being used, in which case we actually return
+ * the label here.
+ *
* @return string
*/
function getLabel() {
- return ' ';
+ if ( $this->mParent instanceof OOUIHTMLForm ) {
+ return $this->mLabel;
+ } else {
+ return ' ';
+ }
+ }
+
+ /**
+ * Get label alignment when generating field for OOUI.
+ * @return string 'left', 'right', 'top' or 'inline'
+ */
+ protected function getLabelAlignOOUI() {
+ return 'inline';
}
/**
$rows = $this->mParams['rows'];
$columns = $this->mParams['columns'];
- $attribs = $this->getAttributes( array( 'disabled', 'tabindex' ) );
+ $mappings = array();
+
+ if ( $this->mParent instanceof OOUIHTMLForm ) {
+ $mappings['tabindex'] = 'tabIndex';
+ }
+
+ $attribs = $this->getAttributes( array( 'disabled', 'tabindex' ), $mappings );
// Build the column headers
$headerContents = Html::rawElement( 'td', array(), ' ' );
$checked = true;
$thisAttribs['disabled'] = 1;
}
- $chkBox = Xml::check( "{$this->mName}[]", $checked, $attribs + $thisAttribs );
+ $chkBox = $this->getOneCheckbox( $checked, $attribs + $thisAttribs );
+
if ( $this->mParent->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) {
$chkBox = Html::openElement( 'div', array( 'class' => 'mw-ui-checkbox' ) ) .
$chkBox .
return $html;
}
+ protected function getOneCheckbox( $checked, $attribs ) {
+ if ( $this->mParent instanceof OOUIHTMLForm ) {
+ return new OOUI\CheckboxInputWidget( array(
+ 'name' => "{$this->mName}[]",
+ 'selected' => $checked,
+ 'value' => '1',
+ ) + $attribs );
+ }
+
+ return Xml::check( "{$this->mName}[]", $checked, $attribs );
+ }
+
protected function isTagForcedOff( $tag ) {
return isset( $this->mParams['force-options-off'] )
&& in_array( $tag, $this->mParams['force-options-off'] );
*/
protected $availableSubclassDisplayFormats = array(
'vform',
+ 'ooui',
);
/**
case 'vform':
$reflector = new ReflectionClass( 'VFormHTMLForm' );
return $reflector->newInstanceArgs( $arguments );
+ case 'ooui':
+ $reflector = new ReflectionClass( 'OOUIHTMLForm' );
+ return $reflector->newInstanceArgs( $arguments );
default:
$reflector = new ReflectionClass( 'HTMLForm' );
$form = $reflector->newInstanceArgs( $arguments );
Html::rawElement( 'tbody', array(), "\n$html\n" ) ) . "\n";
} elseif ( $displayFormat === 'inline' ) {
$html = Html::rawElement( 'span', $attribs, "\n$html\n" );
+ } elseif ( $displayFormat === 'ooui' ) {
+ $config = array(
+ 'classes' => $classes,
+ );
+ if ( $sectionName ) {
+ $config['id'] = Sanitizer::escapeId( $sectionName );
+ }
+ $fieldset = new OOUI\FieldsetLayout( $config );
+ // Ewww. We should pass this as $config['items'], but there might be string snippets.
+ $fieldset->group->appendContent( new OOUI\HtmlSnippet( $html ) );
+ $html = $fieldset->toString();
} else {
$html = Html::rawElement( 'div', $attribs, "\n$html\n" );
}
*/
abstract function getInputHTML( $value );
+ /**
+ * Same as getInputHTML, but returns an OOUI object.
+ * Defaults to false, which getOOUI will interpret as "use the HTML version"
+ *
+ * @param string $value
+ * @return OOUI\Widget|false
+ */
+ function getInputOOUI( $value ) {
+ return false;
+ }
+
/**
* Get a translated interface message
*
return $html;
}
+ /**
+ * Get the OOUI version of the div. Falls back to getDiv by default.
+ * @since 1.26
+ *
+ * @param string $value The value to set the input to.
+ *
+ * @return string
+ */
+ public function getOOUI( $value ) {
+ list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
+
+ $inputField = $this->getInputOOUI( $value );
+
+ if ( !$inputField ) {
+ // This field doesn't have an OOUI implementation yet at all.
+ // OK, use this trick:
+ return $this->getDiv( $value );
+ }
+
+ $infusable = true;
+ if ( is_string( $inputField ) ) {
+ // Mmm… We have an OOUI implementation, but it's not complete, and we got a load of HTML.
+ // Cheat a little and wrap it in a widget! It won't be infusable, though, since client-side
+ // JavaScript doesn't know how to rebuilt the contents.
+ $inputField = new OOUI\Widget( array( 'content' => new OOUI\HtmlSnippet( $inputField ) ) );
+ $infusable = false;
+ }
+
+ $fieldType = get_class( $this );
+ $field = new OOUI\FieldLayout( $inputField, array(
+ 'classes' => array( "mw-htmlform-field-$fieldType", $this->mClass, $errorClass ),
+ 'align' => $this->getLabelAlignOOUI(),
+ 'label' => $this->getLabel(),
+ 'help' => $this->getHelpText(),
+ 'infusable' => $infusable,
+ ) );
+
+ return $field . $errors;
+ }
+
+ /**
+ * Get label alignment when generating field for OOUI.
+ * @return string 'left', 'right', 'top' or 'inline'
+ */
+ protected function getLabelAlignOOUI() {
+ return 'top';
+ }
+
/**
* Get the complete raw fields for the input, including help text,
* labels, and whatever.
return array( $errors, $errorClass );
}
+ /**
+ * @return string
+ */
function getLabel() {
return is_null( $this->mLabel ) ? '' : $this->mLabel;
}
return Linker::tooltipAndAccesskeyAttribs( $this->mParams['tooltip'] );
}
+ /**
+ * Get a translated key if necessary.
+ * @param array|null $mappings Array of mappings, 'original' => 'translated'
+ * @param string $key
+ * @return string
+ */
+ protected function getMappedKey( $mappings, $key ) {
+ if ( !is_array( $mappings ) ) {
+ return $key;
+ }
+
+ if ( !empty( $mappings[$key] ) ) {
+ return $mappings[$key];
+ }
+
+ return $key;
+ }
+
/**
* Returns the given attributes from the parameters
*
* @param array $list List of attributes to get
+ * @param array $mappings Optional - Key/value map of attribute names to use instead of the ones passed in
* @return array Attributes
*/
- public function getAttributes( array $list ) {
+ public function getAttributes( array $list, array $mappings = null ) {
static $boolAttribs = array( 'disabled', 'required', 'autofocus', 'multiple', 'readonly' );
$ret = array();
-
foreach ( $list as $key ) {
+ $mappedKey = $this->getMappedKey( $mappings, $key );
+
if ( in_array( $key, $boolAttribs ) ) {
if ( !empty( $this->mParams[$key] ) ) {
- $ret[$key] = '';
+ $ret[$mappedKey] = '';
}
} elseif ( isset( $this->mParams[$key] ) ) {
- $ret[$key] = $this->mParams[$key];
+ $ret[$mappedKey] = $this->mParams[$key];
}
}
return $this->mOptions;
}
+ /**
+ * Get options and make them into arrays suitable for OOUI.
+ * @return array Options for inclusion in a select or whatever.
+ */
+ public function getOptionsOOUI() {
+ $oldoptions = $this->getOptions();
+
+ if ( $oldoptions === null ) {
+ return null;
+ }
+
+ $options = array();
+
+ foreach ( $oldoptions as $text => $data ) {
+ $options[] = array(
+ 'data' => $data,
+ 'label' => $text,
+ );
+ }
+
+ return $options;
+ }
+
/**
* flatten an array of options to a single array, for instance,
* a set of "<options>" inside "<optgroups>".
return !empty( $this->mParams['raw'] ) ? $value : htmlspecialchars( $value );
}
+ public function getInputOOUI( $value ) {
+ if ( !empty( $this->mParams['raw'] ) ) {
+ $value = new OOUI\HtmlSnippet( $value );
+ }
+
+ return new OOUI\LabelWidget( array(
+ 'label' => $value,
+ ) );
+ }
+
public function getTableRow( $value ) {
if ( !empty( $this->mParams['rawrow'] ) ) {
return $value;
return $select->getHTML();
}
+
+ function getInputOOUI( $value ) {
+ $disabled = false;
+ $allowedParams = array( 'tabindex' );
+ $attribs = $this->getAttributes( $allowedParams, array( 'tabindex' => 'tabIndex' ) );
+
+ if ( $this->mClass !== '' ) {
+ $attribs['classes'] = array( $this->mClass );
+ }
+
+ if ( !empty( $this->mParams['disabled'] ) ) {
+ $disabled = true;
+ }
+
+ return new OOUI\DropdownInputWidget( array(
+ 'name' => $this->mName,
+ 'id' => $this->mID,
+ 'options' => $this->getOptionsOOUI(),
+ 'value' => strval( $value ),
+ 'disabled' => $disabled,
+ ) + $attribs );
+ }
}
$attribs += $this->getAttributes( $allowedParams );
return Html::textarea( $this->mName, $value, $attribs );
}
+
+ function getInputOOUI( $value ) {
+ $attribs = $this->getTooltipAndAccessKey();
+
+ if ( $this->mClass !== '' ) {
+ $attribs['classes'] = array( $this->mClass );
+ }
+
+ $allowedParams = array(
+ 'placeholder',
+ 'tabindex',
+ 'disabled',
+ 'readonly',
+ 'required',
+ 'autofocus',
+ );
+
+ $attribs += $this->getAttributes( $allowedParams, array(
+ 'tabindex' => 'tabIndex',
+ 'readonly' => 'readOnly',
+ ) );
+
+ return new OOUI\TextInputWidget( array(
+ 'id' => $this->mID,
+ 'name' => $this->mName,
+ 'multiline' => true,
+ 'value' => $value,
+ ) + $attribs );
+ }
}
$attribs += $this->getAttributes( $allowedParams );
# Extract 'type'
+ $type = $this->getType( $attribs );
+ return Html::input( $this->mName, $value, $type, $attribs );
+ }
+
+ protected function getType( &$attribs ) {
$type = isset( $attribs['type'] ) ? $attribs['type'] : 'text';
unset( $attribs['type'] );
}
}
- return Html::input( $this->mName, $value, $type, $attribs );
+ return $type;
+ }
+
+ function getInputOOUI( $value ) {
+ $attribs = $this->getTooltipAndAccessKey();
+
+ if ( $this->mClass !== '' ) {
+ $attribs['classes'] = array( $this->mClass );
+ }
+
+ # @todo Enforce pattern, step, required, readonly on the server side as
+ # well
+ $allowedParams = array(
+ 'autofocus',
+ 'autosize',
+ 'disabled',
+ 'flags',
+ 'indicator',
+ 'maxlength',
+ 'placeholder',
+ 'readonly',
+ 'required',
+ 'tabindex',
+ 'type',
+ );
+
+ $attribs += $this->getAttributes( $allowedParams, array(
+ 'maxlength' => 'maxLength',
+ 'readonly' => 'readOnly',
+ 'tabindex' => 'tabIndex',
+ ) );
+
+ $type = $this->getType( $attribs );
+
+ return new OOUI\TextInputWidget( array(
+ 'id' => $this->mID,
+ 'name' => $this->mName,
+ 'value' => $value,
+ 'type' => $type,
+ ) + $attribs );
}
}
--- /dev/null
+<?php
+
+/**
+ * HTML form generation and submission handling, OOUI style.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Compact stacked vertical format for forms, implemented using OOUI widgets.
+ */
+class OOUIHTMLForm extends HTMLForm {
+ /**
+ * Wrapper and its legend are never generated in OOUI mode.
+ * @var boolean
+ */
+ protected $mWrapperLegend = false;
+
+ public function __construct( $descriptor, $context = null, $messagePrefix = '' ) {
+ $this->getOutput()->enableOOUI();
+ $this->getOutput()->addModules( 'mediawiki.htmlform.ooui' );
+ $this->getOutput()->addModuleStyles( 'mediawiki.htmlform.ooui.styles' );
+ parent::__construct( $descriptor, $context, $messagePrefix );
+ }
+
+ /**
+ * Symbolic display format name.
+ * @var string
+ */
+ protected $displayFormat = 'ooui';
+
+ public static function loadInputFromParameters( $fieldname, $descriptor, HTMLForm $parent = null ) {
+ $field = parent::loadInputFromParameters( $fieldname, $descriptor, $parent );
+ $field->setShowEmptyLabel( false );
+ return $field;
+ }
+
+ function getButtons() {
+ $buttons = '';
+
+ if ( $this->mShowSubmit ) {
+ $attribs = array();
+
+ if ( isset( $this->mSubmitID ) ) {
+ $attribs['id'] = $this->mSubmitID;
+ }
+
+ if ( isset( $this->mSubmitName ) ) {
+ $attribs['name'] = $this->mSubmitName;
+ }
+
+ if ( isset( $this->mSubmitTooltip ) ) {
+ $attribs += Linker::tooltipAndAccesskeyAttribs( $this->mSubmitTooltip );
+ }
+
+ $attribs['classes'] = array(
+ 'mw-htmlform-submit',
+ $this->mSubmitModifierClass,
+ );
+
+ $attribs['type'] = 'submit';
+ $attribs['label'] = $this->getSubmitText();
+ $attribs['value'] = $this->getSubmitText();
+ $attribs['flags'] = array( 'primary', 'constructive' );
+
+ $buttons .= new OOUI\ButtonInputWidget( $attribs );
+ }
+
+ if ( $this->mShowReset ) {
+ $buttons .= new OOUI\ButtonInputWidget( array(
+ 'type' => 'reset',
+ 'label' => $this->msg( 'htmlform-reset' )->text(),
+ ) );
+ }
+
+ foreach ( $this->mButtons as $button ) {
+ $attrs = array();
+
+ if ( $button['attribs'] ) {
+ $attrs += $button['attribs'];
+ }
+
+ if ( isset( $button['id'] ) ) {
+ $attrs['id'] = $button['id'];
+ }
+
+ $attrs['classes'] = isset( $attrs['class'] ) ? (array)$attrs['class'] : array();
+
+ $buttons .= new OOUI\ButtonInputWidget( array(
+ 'type' => 'submit',
+ 'name' => $button['name'],
+ 'value' => $button['value'],
+ 'label' => $button['value'],
+ ) + $attrs );
+ }
+
+ $html = Html::rawElement( 'div',
+ array( 'class' => 'mw-htmlform-submit-buttons' ), "\n$buttons" ) . "\n";
+
+ return $html;
+ }
+
+ function getFormAttributes() {
+ $attribs = parent::getFormAttributes();
+ if ( !isset( $attribs['class'] ) ) {
+ $attribs['class'] = '';
+ }
+
+ if ( is_string( $attribs['class'] ) ) {
+ $attribs['class'] = trim( $attribs['class'] . ' mw-htmlform-ooui' );
+ } else {
+ $attribs['class'][] = 'mw-htmlform-ooui';
+ }
+
+ return $attribs;
+ }
+
+ function wrapForm( $html ) {
+ // Always discard $this->mWrapperLegend
+ return Html::rawElement( 'form', $this->getFormAttributes(), $html );
+ }
+}
'colon-separator',
),
),
+ 'mediawiki.htmlform.ooui' => array(
+ 'scripts' => 'resources/src/mediawiki/mediawiki.htmlform.ooui.js',
+ 'dependencies' => 'oojs-ui',
+ ),
+ 'mediawiki.htmlform.ooui.styles' => array(
+ 'styles' => 'resources/src/mediawiki/mediawiki.htmlform.ooui.css',
+ ),
'mediawiki.icon' => array(
'styles' => 'resources/src/mediawiki/mediawiki.icon.less',
),
--- /dev/null
+/* OOUIHTMLForm styles */
+
+.mw-htmlform-ooui {
+ width: 50em;
+}
+
+.mw-htmlform-ooui .mw-htmlform-submit-buttons {
+ margin-top: 1em;
+}
+
+.mw-htmlform-ooui .mw-htmlform-field-HTMLCheckMatrix,
+.mw-htmlform-ooui .mw-htmlform-matrix,
+.mw-htmlform-ooui .mw-htmlform-matrix tr {
+ width: 100%;
+}
+
+.mw-htmlform-ooui .mw-htmlform-matrix tr td.first {
+ margin-right: 5%;
+ width: 39%;
+}
--- /dev/null
+/*global OO */
+jQuery( function ( $ ) {
+
+ // Infuse everything with JavaScript widgets
+ $( '.mw-htmlform-ooui [data-ooui]' ).each( function () {
+ OO.ui.infuse( this.id );
+ } );
+
+} );