(Bug 48952) Show debug output in toolbar
[lhc/web/wiklou.git] / includes / HTMLForm.php
index 64498fd..33e447e 100644 (file)
@@ -83,9 +83,8 @@
  * $form = new HTMLForm( $someFields );
  * $form->setMethod( 'get' )
  *      ->setWrapperLegendMsg( 'message-key' )
- *      ->suppressReset()
  *      ->prepareForm()
- *      ->displayForm();
+ *      ->displayForm( '' );
  * @endcode
  * Note that you will have prepareForm and displayForm at the end. Other
  * methods call done after that would simply not be part of the form :(
@@ -141,6 +140,7 @@ class HTMLForm extends ContextSource {
        protected $mSectionFooters = array();
        protected $mPost = '';
        protected $mId;
+       protected $mTableId = '';
 
        protected $mSubmitID;
        protected $mSubmitName;
@@ -201,12 +201,12 @@ class HTMLForm extends ContextSource {
                        $this->setContext( $context );
                        $this->mTitle = false; // We don't need them to set a title
                        $this->mMessagePrefix = $messagePrefix;
-               } else {
+               } elseif ( is_null( $context ) && $messagePrefix !== '' ) {
+                       $this->mMessagePrefix = $messagePrefix;
+               } elseif ( is_string( $context ) && $messagePrefix === '' ) {
                        // B/C since 1.18
-                       if ( is_string( $context ) && $messagePrefix === '' ) {
-                               // it's actually $messagePrefix
-                               $this->mMessagePrefix = $context;
-                       }
+                       // it's actually $messagePrefix
+                       $this->mMessagePrefix = $context;
                }
 
                // Expand out into a tree.
@@ -588,8 +588,8 @@ class HTMLForm extends ContextSource {
        }
 
        /**
-        * Display the form (sending to $wgOut), with an appropriate error
-        * message or stack of messages, and any validation errors, etc.
+        * Display the form (sending to the context's OutputPage object), with an
+        * appropriate error message or stack of messages, and any validation errors, etc.
         *
         * @attention You should call prepareForm() before calling this function.
         * Moreover, when doing method chaining this should be the very last method
@@ -743,7 +743,7 @@ class HTMLForm extends ContextSource {
         * @return String
         */
        function getBody() {
-               return $this->displaySection( $this->mFieldTree );
+               return $this->displaySection( $this->mFieldTree, $this->mTableId );
        }
 
        /**
@@ -872,6 +872,18 @@ class HTMLForm extends ContextSource {
                return $this;
        }
 
+       /**
+        * Set the id of the \<table\> or outermost \<div\> element.
+        *
+        * @since 1.22
+        * @param string $id new value of the id attribute, or "" to remove
+        * @return HTMLForm $this for chaining calls
+        */
+       public function setTableId( $id ) {
+               $this->mTableId = $id;
+               return $this;
+       }
+
        /**
         * @param string $id DOM id for the form
         * @return HTMLForm $this for chaining calls (since 1.20)
@@ -880,6 +892,7 @@ class HTMLForm extends ContextSource {
                $this->mId = $id;
                return $this;
        }
+
        /**
         * Prompt the whole form to be wrapped in a "<fieldset>", with
         * this text as its "<legend>" element.
@@ -978,7 +991,7 @@ class HTMLForm extends ContextSource {
                                        $hasLabel = true;
                                }
                        } elseif ( is_array( $value ) ) {
-                               $section = $this->displaySection( $value, $key, "$fieldsetIDPrefix$key-" );
+                               $section = $this->displaySection( $value, "mw-htmlform-$key", "$fieldsetIDPrefix$key-" );
                                $legend = $this->getLegend( $key );
                                if ( isset( $this->mSectionHeaders[$key] ) ) {
                                        $section = $this->mSectionHeaders[$key] . $section;
@@ -1006,7 +1019,7 @@ class HTMLForm extends ContextSource {
                        );
 
                        if ( $sectionName ) {
-                               $attribs['id'] = Sanitizer::escapeId( "mw-htmlform-$sectionName" );
+                               $attribs['id'] = Sanitizer::escapeId( $sectionName );
                        }
 
                        if ( $displayFormat === 'table' ) {
@@ -1094,7 +1107,6 @@ class HTMLForm extends ContextSource {
                $this->mAction = $action;
                return $this;
        }
-
 }
 
 /**
@@ -1112,6 +1124,12 @@ abstract class HTMLFormField {
        protected $mClass = '';
        protected $mDefault;
 
+       /**
+        * @var bool If true will generate an empty div element with no label
+        * @since 1.22
+        */
+       protected $mShowEmptyLabels = true;
+
        /**
         * @var HTMLForm
         */
@@ -1204,6 +1222,8 @@ abstract class HTMLFormField {
        /**
         * Initialise the object
         * @param array $params Associative Array. See HTMLForm doc for syntax.
+        *
+        * @since 1.22 The 'label' attribute no longer accepts raw HTML, use 'label-raw' instead
         * @throws MWException
         */
        function __construct( $params ) {
@@ -1222,7 +1242,14 @@ abstract class HTMLFormField {
 
                        $this->mLabel = wfMessage( $msg, $msgInfo )->parse();
                } elseif ( isset( $params['label'] ) ) {
-                       $this->mLabel = $params['label'];
+                       if ( $params['label'] === '&#160;' ) {
+                               // Apparently some things set &nbsp directly and in an odd format
+                               $this->mLabel = '&#160;';
+                       } else {
+                               $this->mLabel = htmlspecialchars( $params['label'] );
+                       }
+               } elseif ( isset( $params['label-raw'] ) ) {
+                       $this->mLabel = $params['label-raw'];
                }
 
                $this->mName = "wp{$params['fieldname']}";
@@ -1267,6 +1294,10 @@ abstract class HTMLFormField {
                if ( isset( $params['flatlist'] ) ) {
                        $this->mClass .= ' mw-htmlform-flatlist';
                }
+
+               if ( isset( $params['hidelabel'] ) ) {
+                       $this->mShowEmptyLabels = false;
+               }
        }
 
        /**
@@ -1327,9 +1358,14 @@ abstract class HTMLFormField {
                $cellAttributes = array();
                $label = $this->getLabelHtml( $cellAttributes );
 
+               $outerDivClass = array(
+                       'mw-input',
+                       'mw-htmlform-nolabel' => ( $label === '' )
+               );
+
                $field = Html::rawElement(
                        'div',
-                       array( 'class' => 'mw-input' ) + $cellAttributes,
+                       array( 'class' => $outerDivClass ) + $cellAttributes,
                        $inputHtml . "\n$errors"
                );
                $html = Html::rawElement( 'div',
@@ -1458,7 +1494,7 @@ abstract class HTMLFormField {
        }
 
        function getLabel() {
-               return $this->mLabel;
+               return is_null( $this->mLabel ) ? '' : $this->mLabel;
        }
 
        function getLabelHtml( $cellAttributes = array() ) {
@@ -1470,20 +1506,32 @@ abstract class HTMLFormField {
                        $for['for'] = $this->mID;
                }
 
+               $labelValue = trim( $this->getLabel() );
+               $hasLabel = false;
+               if ( $labelValue !== '&#160;' && $labelValue !== '' ) {
+                       $hasLabel = true;
+               }
+
                $displayFormat = $this->mParent->getDisplayFormat();
-               $labelElement = Html::rawElement( 'label', $for, $this->getLabel() );
+               $html = '';
 
-               if ( $displayFormat == 'table' ) {
-                       return Html::rawElement( 'td', array( 'class' => 'mw-label' ) + $cellAttributes,
-                               Html::rawElement( 'label', $for, $this->getLabel() )
+               if ( $displayFormat === 'table' ) {
+                       $html = Html::rawElement( 'td', array( 'class' => 'mw-label' ) + $cellAttributes,
+                               Html::rawElement( 'label', $for, $labelValue )
                        );
-               } elseif ( $displayFormat == 'div' ) {
-                       return Html::rawElement( 'div', array( 'class' => 'mw-label' ) + $cellAttributes,
-                               Html::rawElement( 'label', $for, $this->getLabel() )
-                       );
-               } else {
-                       return $labelElement;
+               } elseif ( $hasLabel || $this->mShowEmptyLabels ) {
+                       if ( $displayFormat === 'div' ) {
+                               $html = Html::rawElement(
+                                       'div',
+                                       array( 'class' => 'mw-label' ) + $cellAttributes,
+                                       Html::rawElement( 'label', $for, $labelValue )
+                               );
+                       } else {
+                               $html = Html::rawElement( 'label', $for, $labelValue );
+                       }
                }
+
+               return $html;
        }
 
        function getDefault() {
@@ -1623,16 +1671,19 @@ class HTMLTextField extends HTMLFormField {
        }
 }
 class HTMLTextAreaField extends HTMLFormField {
+       const DEFAULT_COLS = 80;
+       const DEFAULT_ROWS = 25;
+
        function getCols() {
                return isset( $this->mParams['cols'] )
                        ? $this->mParams['cols']
-                       : 80;
+                       : static::DEFAULT_COLS;
        }
 
        function getRows() {
                return isset( $this->mParams['rows'] )
                        ? $this->mParams['rows']
-                       : 25;
+                       : static::DEFAULT_ROWS;
        }
 
        function getInputHTML( $value ) {
@@ -1811,12 +1862,18 @@ class HTMLCheckField extends HTMLFormField {
  * are of the form "columnName-rowName"
  *
  * Options:
- *   columns:           Required list of columns in the matrix.
- *   rows:              Required list of rows in the matrix.
- *   force-options-on:  Accepts array of column-row tags to be displayed as enabled
- *                      but unavailable to change
- *   force-options-off: Accepts array of column-row tags to be displayed as disabled
- *                      but unavailable to change.
+ *   - columns
+ *     - Required list of columns in the matrix.
+ *   - rows
+ *     - Required list of rows in the matrix.
+ *   - force-options-on
+ *     - Accepts array of column-row tags to be displayed as enabled but unavailable to change
+ *   - force-options-off
+ *     - Accepts array of column-row tags to be displayed as disabled but unavailable to change.
+ *   - tooltips
+ *     - Optional array mapping row label to tooltip content
+ *   - tooltip-class
+ *     - Optional CSS class used on tooltip container span. Defaults to mw-icon-question.
  */
 class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
 
@@ -1893,8 +1950,21 @@ class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
                }
                $tableContents .= Html::rawElement( 'tr', array(), "\n$headerContents\n" );
 
+               $tooltipClass = 'mw-icon-question';
+               if ( isset( $this->mParams['tooltip-class'] ) ) {
+                       $tooltipClass = $this->mParams['tooltip-class'];
+               }
+
                // Build the options matrix
                foreach ( $rows as $rowLabel => $rowTag ) {
+                       // Append tooltip if configured
+                       if ( isset( $this->mParams['tooltips'][$rowLabel] ) ) {
+                               $tooltipAttribs = array(
+                                       'class' => "mw-htmlform-tooltip $tooltipClass",
+                                       'title' =>  $this->mParams['tooltips'][$rowLabel],
+                               );
+                               $rowLabel .= ' ' . Html::element( 'span', $tooltipAttribs, '' );
+                       }
                        $rowContents = Html::rawElement( 'td', array(), $rowLabel );
                        foreach ( $columns as $columnTag ) {
                                $thisTag = "$columnTag-$rowTag";
@@ -1903,7 +1973,7 @@ class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
                                        'id' => "{$this->mID}-$thisTag",
                                        'value' => $thisTag,
                                );
-                               $checked = in_array( $thisTag, (array)$value, true);
+                               $checked = in_array( $thisTag, (array)$value, true );
                                if ( $this->isTagForcedOff( $thisTag ) ) {
                                        $checked = false;
                                        $thisAttribs['disabled'] = 1;
@@ -2012,7 +2082,7 @@ class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
                                $thisTag = "$column-$row";
                                if ( $this->isTagForcedOff( $thisTag ) ) {
                                        $res[$thisTag] = false;
-                               } elseif ($this->isTagForcedOn( $thisTag ) ) {
+                               } elseif ( $this->isTagForcedOn( $thisTag ) ) {
                                        $res[$thisTag] = true;
                                } else {
                                        $res[$thisTag] = in_array( $thisTag, $data );
@@ -2610,7 +2680,19 @@ class HTMLHiddenField extends HTMLFormField {
  * Add a submit button inline in the form (as opposed to
  * HTMLForm::addButton(), which will add it at the end).
  */
-class HTMLSubmitField extends HTMLFormField {
+class HTMLSubmitField extends HTMLButtonField {
+       protected $buttonType = 'submit';
+}
+
+/**
+ * Adds a generic button inline to the form. Does not do anything, you must add
+ * click handling code in JavaScript. Use a HTMLSubmitField if you merely
+ * wish to add a submit button to a form.
+ *
+ * @since 1.22
+ */
+class HTMLButtonField extends HTMLFormField {
+       protected $buttonType = 'button';
 
        public function __construct( $info ) {
                $info['nodata'] = true;
@@ -2620,7 +2702,6 @@ class HTMLSubmitField extends HTMLFormField {
        public function getInputHTML( $value ) {
                $attr = array(
                        'class' => 'mw-htmlform-submit ' . $this->mClass,
-                       'name' => $this->mName,
                        'id' => $this->mID,
                );
 
@@ -2628,7 +2709,12 @@ class HTMLSubmitField extends HTMLFormField {
                        $attr['disabled'] = 'disabled';
                }
 
-               return Xml::submitButton( $value, $attr );
+               return Html::input(
+                       $this->mName,
+                       $value,
+                       $this->buttonType,
+                       $attr
+               );
        }
 
        protected function needsLabel() {