From 8b48c99889c9cf9024a1119bbbb6330b4e15c142 Mon Sep 17 00:00:00 2001 From: mainframe98 Date: Thu, 22 Mar 2018 20:46:54 +0100 Subject: [PATCH] Add OOUI for HTMLFormFieldCloner The JavaScript for the cloner fields has been updated to function when using OOUI Cloners. The buttons are packed quite tight together, but there does not seem to be any CSS that enforced the spacing that I could find. Bug: T171666 Change-Id: Iba6eed9d6cee922d56855bbe2e836956bfd90f42 --- .../htmlform/fields/HTMLFormFieldCloner.php | 143 +++++++++++++++--- resources/src/mediawiki.htmlform/cloner.js | 67 +++++--- 2 files changed, 168 insertions(+), 42 deletions(-) diff --git a/includes/htmlform/fields/HTMLFormFieldCloner.php b/includes/htmlform/fields/HTMLFormFieldCloner.php index aae3af262f..cdbd84da2d 100644 --- a/includes/htmlform/fields/HTMLFormFieldCloner.php +++ b/includes/htmlform/fields/HTMLFormFieldCloner.php @@ -11,7 +11,7 @@ * of fields. * required - If specified, at least one group of fields must be submitted. * format - HTMLForm display format to use when displaying the subfields: - * 'table', 'div', or 'raw'. + * 'table', 'div', or 'raw'. This is ignored when using OOUI. * row-legend - If non-empty, each group of subfields will be enclosed in a * fieldset. The value is the name of a message key to use as the legend. * create-button-message - Message to use as the text of the button to @@ -303,22 +303,12 @@ class HTMLFormFieldCloner extends HTMLFormField { } if ( !isset( $fields['delete'] ) ) { - $name = "{$this->mName}[$key][delete]"; - $label = $this->mParams['delete-button-message'] ?? 'htmlform-cloner-delete'; - $field = HTMLForm::loadInputFromParameters( $name, [ - 'type' => 'submit', - 'formnovalidate' => true, - 'name' => $name, - 'id' => Sanitizer::escapeIdForAttribute( "{$this->mID}--$key--delete" ), - 'cssclass' => 'mw-htmlform-cloner-delete-button', - 'default' => $this->getMessage( $label )->text(), - ], $this->mParent ); - $v = $field->getDefault(); + $field = $this->getDeleteButtonHtml( $key ); if ( $displayFormat === 'table' ) { - $html .= $field->$getFieldHtmlMethod( $v ); + $html .= $field->$getFieldHtmlMethod( $field->getDefault() ); } else { - $html .= $field->getInputHTML( $v ); + $html .= $field->getInputHTML( $field->getDefault() ); } } @@ -354,6 +344,37 @@ class HTMLFormFieldCloner extends HTMLFormField { return $html; } + /** + * @param string $key Array key indicating to which field the delete button belongs + * @return HTMLFormField + */ + protected function getDeleteButtonHtml( $key ) : HTMLFormField { + $name = "{$this->mName}[$key][delete]"; + $label = $this->mParams['delete-button-message'] ?? 'htmlform-cloner-delete'; + $field = HTMLForm::loadInputFromParameters( $name, [ + 'type' => 'submit', + 'formnovalidate' => true, + 'name' => $name, + 'id' => Sanitizer::escapeIdForAttribute( "{$this->mID}--$key--delete" ), + 'cssclass' => 'mw-htmlform-cloner-delete-button', + 'default' => $this->getMessage( $label )->text(), + ], $this->mParent ); + return $field; + } + + protected function getCreateButtonHtml() : HTMLFormField { + $name = "{$this->mName}[create]"; + $label = $this->mParams['create-button-message'] ?? 'htmlform-cloner-create'; + return HTMLForm::loadInputFromParameters( $name, [ + 'type' => 'submit', + 'formnovalidate' => true, + 'name' => $name, + 'id' => Sanitizer::escapeIdForAttribute( "{$this->mID}--create" ), + 'cssclass' => 'mw-htmlform-cloner-create-button', + 'default' => $this->getMessage( $label )->text(), + ], $this->mParent ); + } + public function getInputHTML( $values ) { $html = ''; @@ -374,18 +395,92 @@ class HTMLFormFieldCloner extends HTMLFormField { 'data-unique-id' => $this->uniqueId, ], $html ); - $name = "{$this->mName}[create]"; - $label = $this->mParams['create-button-message'] ?? 'htmlform-cloner-create'; - $field = HTMLForm::loadInputFromParameters( $name, [ - 'type' => 'submit', - 'formnovalidate' => true, - 'name' => $name, - 'id' => Sanitizer::escapeIdForAttribute( "{$this->mID}--create" ), - 'cssclass' => 'mw-htmlform-cloner-create-button', - 'default' => $this->getMessage( $label )->text(), - ], $this->mParent ); + $field = $this->getCreateButtonHtml(); $html .= $field->getInputHTML( $field->getDefault() ); return $html; } + + /** + * Get the input OOUI HTML for the specified key. + * + * @param string $key Array key under which the fields should be named + * @param array $values + * @return string + */ + protected function getInputOOUIForKey( $key, array $values ) { + $html = ''; + $hidden = ''; + + $fields = $this->createFieldsForKey( $key ); + foreach ( $fields as $fieldname => $field ) { + $v = array_key_exists( $fieldname, $values ) + ? $values[$fieldname] + : $field->getDefault(); + + if ( $field instanceof HTMLHiddenField ) { + // HTMLHiddenField doesn't generate its own HTML + list( $name, $value, $params ) = $field->getHiddenFieldData( $v ); + $hidden .= Html::hidden( $name, $value, $params ) . "\n"; + } else { + $html .= $field->getOOUI( $v ); + } + } + + if ( !isset( $fields['delete'] ) ) { + $field = $this->getDeleteButtonHtml( $key ); + $fieldHtml = $field->getInputOOUI( $field->getDefault() ); + $fieldHtml->setInfusable( true ); + + $html .= $fieldHtml; + } + + $classes = [ + 'mw-htmlform-cloner-row', + ]; + + $attribs = [ + 'class' => implode( ' ', $classes ), + ]; + + $html = Html::rawElement( 'div', $attribs, "\n$html\n" ); + + $html .= $hidden; + + if ( !empty( $this->mParams['row-legend'] ) ) { + $legend = $this->msg( $this->mParams['row-legend'] )->text(); + $html = Xml::fieldset( $legend, $html ); + } + + return $html; + } + + public function getInputOOUI( $values ) { + $html = ''; + + foreach ( (array)$values as $key => $value ) { + if ( $key === 'nonjs' ) { + continue; + } + $html .= Html::rawElement( 'li', [ 'class' => 'mw-htmlform-cloner-li' ], + $this->getInputOOUIForKey( $key, $value ) + ); + } + + $template = $this->getInputOOUIForKey( $this->uniqueId, [] ); + $html = Html::rawElement( 'ul', [ + 'id' => "mw-htmlform-cloner-list-{$this->mID}", + 'class' => 'mw-htmlform-cloner-ul', + 'data-template' => $template, + 'data-unique-id' => $this->uniqueId, + ], $html ); + + $field = $this->getCreateButtonHtml(); + $fieldHtml = $field->getInputOOUI( $field->getDefault() ); + $fieldHtml->setInfusable( true ); + + $html .= $fieldHtml; + + return $html; + } } diff --git a/resources/src/mediawiki.htmlform/cloner.js b/resources/src/mediawiki.htmlform/cloner.js index 4d94deb0e7..6e33856daf 100644 --- a/resources/src/mediawiki.htmlform/cloner.js +++ b/resources/src/mediawiki.htmlform/cloner.js @@ -6,31 +6,62 @@ var cloneCounter = 0; - mw.hook( 'htmlform.enhance' ).add( function ( $root ) { - $root.find( '.mw-htmlform-cloner-delete-button' ).filter( ':input' ).click( function ( ev ) { - ev.preventDefault(); - $( this ).closest( 'li.mw-htmlform-cloner-li' ).remove(); - } ); - - $root.find( '.mw-htmlform-cloner-create-button' ).filter( ':input' ).click( function ( ev ) { - var $ul, $li, html; - - ev.preventDefault(); - - $ul = $( this ).prev( 'ul.mw-htmlform-cloner-ul' ); - + /** + * Appends a new row with fields to the cloner. + * + * @ignore + * @param {jQuery} $createButton + */ + function appendToCloner( $createButton ) { + var $li, + $ul = $createButton.prev( 'ul.mw-htmlform-cloner-ul' ), html = $ul.data( 'template' ).replace( new RegExp( mw.RegExp.escape( $ul.data( 'uniqueId' ) ), 'g' ), 'clone' + ( ++cloneCounter ) ); - $li = $( '
  • ' ) - .addClass( 'mw-htmlform-cloner-li' ) - .html( html ) - .appendTo( $ul ); + $li = $( '
  • ' ) + .addClass( 'mw-htmlform-cloner-li' ) + .html( html ) + .appendTo( $ul ); - mw.hook( 'htmlform.enhance' ).fire( $li ); + mw.hook( 'htmlform.enhance' ).fire( $li ); + } + + mw.hook( 'htmlform.enhance' ).add( function ( $root ) { + var $deleteElement = $root.find( '.mw-htmlform-cloner-delete-button' ), + $createElement = $root.find( '.mw-htmlform-cloner-create-button' ), + createButton; + + $deleteElement.each( function () { + var $element = $( this ), + deleteButton; + + if ( $element.hasClass( 'oo-ui-widget' ) ) { + deleteButton = OO.ui.infuse( $element ); + deleteButton.on( 'click', function () { + deleteButton.$element.closest( 'li.mw-htmlform-cloner-li' ).remove(); + } ); + } else { + $element.filter( ':input' ).click( function ( ev ) { + ev.preventDefault(); + $( this ).closest( 'li.mw-htmlform-cloner-li' ).remove(); + } ); + } } ); + + if ( $createElement.hasClass( 'oo-ui-widget' ) ) { + createButton = OO.ui.infuse( $createElement ); + createButton.on( 'click', function () { + appendToCloner( createButton.$element ); + } ); + } else { + $createElement.filter( ':input' ).click( function ( ev ) { + ev.preventDefault(); + + appendToCloner( $( this ) ); + } ); + } } ); }() ); -- 2.20.1