Merge "Fix escaping for MSSQL LIKE queries."
[lhc/web/wiklou.git] / includes / pager / TablePager.php
index 19538c6..0a89e4e 100644 (file)
@@ -42,67 +42,117 @@ abstract class TablePager extends IndexPager {
                        $this->mSort = $this->getDefaultSort();
                }
                if ( $this->getRequest()->getBool( 'asc' ) ) {
-                       $this->mDefaultDirection = false;
+                       $this->mDefaultDirection = IndexPager::DIR_ASCENDING;
                } elseif ( $this->getRequest()->getBool( 'desc' ) ) {
-                       $this->mDefaultDirection = true;
+                       $this->mDefaultDirection = IndexPager::DIR_DESCENDING;
                } /* Else leave it at whatever the class default is */
 
                parent::__construct();
        }
 
+       /**
+        * Get the formatted result list. Calls getStartBody(), formatRow() and getEndBody(), concatenates
+        * the results and returns them.
+        *
+        * Also adds the required styles to our OutputPage object (this means that if context wasn't
+        * passed to constructor or otherwise set up, you will get a pager with missing styles).
+        *
+        * This method has been made 'final' in 1.24. There's no reason to override it, and if there exist
+        * any subclasses that do, the style loading hack is probably broken in them. Let's fail fast
+        * rather than mysteriously render things wrong.
+        *
+        * @deprecated since 1.24, use getBodyOutput() or getFullOutput() instead
+        * @return string
+        */
+       final public function getBody() {
+               $this->getOutput()->addModuleStyles( $this->getModuleStyles() );
+               return parent::getBody();
+       }
+
+       /**
+        * Get the formatted result list.
+        *
+        * Calls getBody() and getModuleStyles() and builds a ParserOutput object. (This is a bit hacky
+        * but works well.)
+        *
+        * @since 1.24
+        * @return ParserOutput
+        */
+       public function getBodyOutput() {
+               $body = parent::getBody();
+
+               $pout = new ParserOutput;
+               $pout->setText( $body );
+               $pout->addModuleStyles( $this->getModuleStyles() );
+               return $pout;
+       }
+
+       /**
+        * Get the formatted result list, with navigation bars.
+        *
+        * Calls getBody(), getNavigationBar() and getModuleStyles() and
+        * builds a ParserOutput object. (This is a bit hacky but works well.)
+        *
+        * @since 1.24
+        * @return ParserOutput
+        */
+       public function getFullOutput() {
+               $navigation = $this->getNavigationBar();
+               $body = parent::getBody();
+
+               $pout = new ParserOutput;
+               $pout->setText( $navigation . $body . $navigation );
+               $pout->addModuleStyles( $this->getModuleStyles() );
+               return $pout;
+       }
+
        /**
         * @protected
         * @return string
         */
        function getStartBody() {
-               global $wgStylePath;
                $sortClass = $this->getSortHeaderClass();
 
                $s = '';
                $fields = $this->getFieldNames();
 
-               # Make table header
+               // Make table header
                foreach ( $fields as $field => $name ) {
                        if ( strval( $name ) == '' ) {
-                               $s .= Html::rawElement( 'th', array(), ' ' ) . "\n";
+                               $s .= Html::rawElement( 'th', [], ' ' ) . "\n";
                        } elseif ( $this->isFieldSortable( $field ) ) {
-                               $query = array( 'sort' => $field, 'limit' => $this->mLimit );
-                               if ( $field == $this->mSort ) {
-                                       # This is the sorted column
-                                       # Prepare a link that goes in the other sort order
-                                       if ( $this->mDefaultDirection ) {
-                                               # Descending
-                                               $image = 'Arr_d.png';
+                               $query = [ 'sort' => $field, 'limit' => $this->mLimit ];
+                               $linkType = null;
+                               $class = null;
+
+                               if ( $this->mSort == $field ) {
+                                       // The table is sorted by this field already, make a link to sort in the other direction
+                                       // We don't actually know in which direction other fields will be sorted by default…
+                                       if ( $this->mDefaultDirection == IndexPager::DIR_DESCENDING ) {
+                                               $linkType = 'asc';
+                                               $class = "$sortClass TablePager_sort-descending";
                                                $query['asc'] = '1';
                                                $query['desc'] = '';
-                                               $alt = $this->msg( 'descending_abbrev' )->escaped();
                                        } else {
-                                               # Ascending
-                                               $image = 'Arr_u.png';
+                                               $linkType = 'desc';
+                                               $class = "$sortClass TablePager_sort-ascending";
                                                $query['asc'] = '';
                                                $query['desc'] = '1';
-                                               $alt = $this->msg( 'ascending_abbrev' )->escaped();
                                        }
-                                       $image = "$wgStylePath/common/images/$image";
-                                       $link = $this->makeLink(
-                                               Html::element( 'img', array( 'width' => 12, 'height' => 12,
-                                                       'alt' => $alt, 'src' => $image ) ) . htmlspecialchars( $name ), $query );
-                                       $s .= Html::rawElement( 'th', array( 'class' => $sortClass ), $link ) . "\n";
-                               } else {
-                                       $s .= Html::rawElement( 'th', array(),
-                                               $this->makeLink( htmlspecialchars( $name ), $query ) ) . "\n";
                                }
+
+                               $link = $this->makeLink( htmlspecialchars( $name ), $query, $linkType );
+                               $s .= Html::rawElement( 'th', [ 'class' => $class ], $link ) . "\n";
                        } else {
-                               $s .= Html::element( 'th', array(), $name ) . "\n";
+                               $s .= Html::element( 'th', [], $name ) . "\n";
                        }
                }
 
                $tableClass = $this->getTableClass();
-               $ret = Html::openElement( 'table', array(
-                       'style' => 'border:1px;',
-                       'class' => "mw-datatable $tableClass" )
+               $ret = Html::openElement( 'table', [
+                       'class' => "mw-datatable $tableClass" ]
                );
-               $ret .= Html::rawElement( 'thead', array(), Html::rawElement( 'tr', array(), "\n" . $s . "\n" ) );
+               $ret .= Html::rawElement( 'thead', [], Html::rawElement( 'tr', [], "\n" . $s . "\n" ) );
                $ret .= Html::openElement( 'tbody' ) . "\n";
 
                return $ret;
@@ -123,8 +173,8 @@ abstract class TablePager extends IndexPager {
        function getEmptyBody() {
                $colspan = count( $this->getFieldNames() );
                $msgEmpty = $this->msg( 'table_pager_empty' )->text();
-               return Html::rawElement( 'tr', array(),
-                       Html::element( 'td', array( 'colspan' => $colspan ), $msgEmpty ) );
+               return Html::rawElement( 'tr', [],
+                       Html::element( 'td', [ 'colspan' => $colspan ], $msgEmpty ) );
        }
 
        /**
@@ -177,12 +227,19 @@ abstract class TablePager extends IndexPager {
                $class = $this->getRowClass( $row );
                if ( $class === '' ) {
                        // Return an empty array to avoid clutter in HTML like class=""
-                       return array();
+                       return [];
                } else {
-                       return array( 'class' => $this->getRowClass( $row ) );
+                       return [ 'class' => $this->getRowClass( $row ) ];
                }
        }
 
+       /**
+        * @return stdClass
+        */
+       protected function getCurrentRow() {
+               return $this->mCurrentRow;
+       }
+
        /**
         * Get any extra attributes to be applied to the given cell. Don't
         * take this as an excuse to hardcode styles; use classes and
@@ -195,7 +252,7 @@ abstract class TablePager extends IndexPager {
         * @return array Array of attr => value
         */
        function getCellAttrs( $field, $value ) {
-               return array( 'class' => 'TablePager_col_' . $field );
+               return [ 'class' => 'TablePager_col_' . $field ];
        }
 
        /**
@@ -207,26 +264,23 @@ abstract class TablePager extends IndexPager {
        }
 
        /**
-        * @protected
         * @return string
         */
-       function getTableClass() {
+       protected function getTableClass() {
                return 'TablePager';
        }
 
        /**
-        * @protected
         * @return string
         */
-       function getNavClass() {
+       protected function getNavClass() {
                return 'TablePager_nav';
        }
 
        /**
-        * @protected
         * @return string
         */
-       function getSortHeaderClass() {
+       protected function getSortHeaderClass() {
                return 'TablePager_sort';
        }
 
@@ -235,65 +289,57 @@ abstract class TablePager extends IndexPager {
         * @return string HTML
         */
        public function getNavigationBar() {
-               global $wgStylePath;
-
                if ( !$this->isNavigationBarShown() ) {
                        return '';
                }
 
-               $path = "$wgStylePath/common/images";
-               $labels = array(
+               $labels = [
                        'first' => 'table_pager_first',
                        'prev' => 'table_pager_prev',
                        'next' => 'table_pager_next',
                        'last' => 'table_pager_last',
-               );
-               $images = array(
-                       'first' => 'arrow_first_25.png',
-                       'prev' => 'arrow_left_25.png',
-                       'next' => 'arrow_right_25.png',
-                       'last' => 'arrow_last_25.png',
-               );
-               $disabledImages = array(
-                       'first' => 'arrow_disabled_first_25.png',
-                       'prev' => 'arrow_disabled_left_25.png',
-                       'next' => 'arrow_disabled_right_25.png',
-                       'last' => 'arrow_disabled_last_25.png',
-               );
-               if ( $this->getLanguage()->isRTL() ) {
-                       $keys = array_keys( $labels );
-                       $images = array_combine( $keys, array_reverse( $images ) );
-                       $disabledImages = array_combine( $keys, array_reverse( $disabledImages ) );
-               }
+               ];
 
-               $linkTexts = array();
-               $disabledTexts = array();
+               $linkTexts = [];
+               $disabledTexts = [];
                foreach ( $labels as $type => $label ) {
                        $msgLabel = $this->msg( $label )->escaped();
-                       $linkTexts[$type] = Html::element( 'img', array( 'src' => "$path/{$images[$type]}",
-                               'alt' => $msgLabel ) ) . "<br />$msgLabel";
-                       $disabledTexts[$type] = Html::element( 'img', array( 'src' => "$path/{$disabledImages[$type]}",
-                               'alt' => $msgLabel ) ) . "<br />$msgLabel";
+                       $linkTexts[$type] = "<div class='TablePager_nav-enabled'>$msgLabel</div>";
+                       $disabledTexts[$type] = "<div class='TablePager_nav-disabled'>$msgLabel</div>";
                }
                $links = $this->getPagingLinks( $linkTexts, $disabledTexts );
 
-               $s = Html::openElement( 'table', array( 'class' => $this->getNavClass() ) );
+               $s = Html::openElement( 'table', [ 'class' => $this->getNavClass() ] );
                $s .= Html::openElement( 'tr' ) . "\n";
                $width = 100 / count( $links ) . '%';
                foreach ( $labels as $type => $label ) {
-                       $s .= Html::rawElement( 'td', array( 'style' => "width:$width;" ), $links[$type] ) . "\n";
+                       // We want every cell to have the same width. We could use table-layout: fixed; in CSS,
+                       // but it only works if we specify the width of a cell or the table and we don't want to.
+                       // There is no better way. <http://www.w3.org/TR/CSS2/tables.html#fixed-table-layout>
+                       $s .= Html::rawElement( 'td',
+                               [ 'style' => "width: $width;", 'class' => "TablePager_nav-$type" ],
+                               $links[$type] ) . "\n";
                }
                $s .= Html::closeElement( 'tr' ) . Html::closeElement( 'table' ) . "\n";
                return $s;
        }
 
+       /**
+        * ResourceLoader modules that must be loaded to provide correct styling for this pager
+        * @since 1.24
+        * @return string[]
+        */
+       public function getModuleStyles() {
+               return [ 'mediawiki.pager.tablePager' ];
+       }
+
        /**
         * Get a "<select>" element which has options for each of the allowed limits
         *
         * @param string $attribs Extra attributes to set
         * @return string HTML fragment
         */
-       public function getLimitSelect( $attribs = array() ) {
+       public function getLimitSelect( $attribs = [] ) {
                $select = new XmlSelect( 'limit', false, $this->mLimit );
                $select->addOptions( $this->getLimitSelectList() );
                foreach ( $attribs as $name => $value ) {
@@ -316,7 +362,7 @@ abstract class TablePager extends IndexPager {
                        $this->mLimitsShown[] = $this->mLimit;
                        sort( $this->mLimitsShown );
                }
-               $ret = array();
+               $ret = [];
                foreach ( $this->mLimitsShown as $key => $value ) {
                        # The pair is either $index => $limit, in which case the $value
                        # will be numeric, or $limit => $text, in which case the $value
@@ -341,7 +387,7 @@ abstract class TablePager extends IndexPager {
         * @param array $blacklist Parameters from the request query which should not be resubmitted
         * @return string HTML fragment
         */
-       function getHiddenFields( $blacklist = array() ) {
+       function getHiddenFields( $blacklist = [] ) {
                $blacklist = (array)$blacklist;
                $query = $this->getRequest()->getQueryValues();
                foreach ( $blacklist as $name ) {
@@ -360,14 +406,12 @@ abstract class TablePager extends IndexPager {
         * @return string HTML fragment
         */
        function getLimitForm() {
-               global $wgScript;
-
                return Html::rawElement(
                        'form',
-                       array(
+                       [
                                'method' => 'get',
-                               'action' => $wgScript
-                       ),
+                               'action' => wfScript(),
+                       ],
                        "\n" . $this->getLimitDropdown()
                ) . "\n";
        }
@@ -384,7 +428,7 @@ abstract class TablePager extends IndexPager {
                return $this->msg( 'table_pager_limit' )
                        ->rawParams( $this->getLimitSelect() )->escaped() .
                        "\n<input type=\"submit\" value=\"$msgSubmit\"/>\n" .
-                       $this->getHiddenFields( array( 'limit' ) );
+                       $this->getHiddenFields( [ 'limit' ] );
        }
 
        /**