00001 <?php
00013 interface Pager {
00014 function getNavigationBar();
00015 function getBody();
00016 }
00017
00060 abstract class IndexPager implements Pager {
00061 public $mRequest;
00062 public $mLimitsShown = array( 20, 50, 100, 250, 500 );
00063 public $mDefaultLimit = 50;
00064 public $mOffset, $mLimit;
00065 public $mQueryDone = false;
00066 public $mDb;
00067 public $mPastTheEndRow;
00068
00073 protected $mIndexField;
00076 protected $mOrderType;
00088 public $mDefaultDirection;
00089 public $mIsBackwards;
00090
00092 public $mIsFirst;
00093
00097 public $mResult;
00098
00099 public function __construct() {
00100 global $wgRequest, $wgUser;
00101 $this->mRequest = $wgRequest;
00102
00103 # NB: the offset is quoted, not validated. It is treated as an
00104 # arbitrary string to support the widest variety of index types. Be
00105 # careful outputting it into HTML!
00106 $this->mOffset = $this->mRequest->getText( 'offset' );
00107
00108 # Use consistent behavior for the limit options
00109 $this->mDefaultLimit = intval( $wgUser->getOption( 'rclimit' ) );
00110 list( $this->mLimit, ) = $this->mRequest->getLimitOffset();
00111
00112 $this->mIsBackwards = ( $this->mRequest->getVal( 'dir' ) == 'prev' );
00113 $this->mDb = wfGetDB( DB_SLAVE );
00114
00115 $index = $this->getIndexField();
00116 $order = $this->mRequest->getVal( 'order' );
00117 if( is_array( $index ) && isset( $index[$order] ) ) {
00118 $this->mOrderType = $order;
00119 $this->mIndexField = $index[$order];
00120 } elseif( is_array( $index ) ) {
00121 # First element is the default
00122 reset( $index );
00123 list( $this->mOrderType, $this->mIndexField ) = each( $index );
00124 } else {
00125 # $index is not an array
00126 $this->mOrderType = null;
00127 $this->mIndexField = $index;
00128 }
00129
00130 if( !isset( $this->mDefaultDirection ) ) {
00131 $dir = $this->getDefaultDirections();
00132 $this->mDefaultDirection = is_array( $dir )
00133 ? $dir[$this->mOrderType]
00134 : $dir;
00135 }
00136 }
00137
00143 function doQuery() {
00144 # Use the child class name for profiling
00145 $fname = __METHOD__ . ' (' . get_class( $this ) . ')';
00146 wfProfileIn( $fname );
00147
00148 $descending = ( $this->mIsBackwards == $this->mDefaultDirection );
00149 # Plus an extra row so that we can tell the "next" link should be shown
00150 $queryLimit = $this->mLimit + 1;
00151
00152 $this->mResult = $this->reallyDoQuery(
00153 $this->mOffset,
00154 $queryLimit,
00155 $descending
00156 );
00157 $this->extractResultInfo( $this->mOffset, $queryLimit, $this->mResult );
00158 $this->mQueryDone = true;
00159
00160 $this->preprocessResults( $this->mResult );
00161 $this->mResult->rewind();
00162
00163 wfProfileOut( $fname );
00164 }
00165
00169 function getResult() {
00170 return $this->mResult;
00171 }
00172
00176 function setOffset( $offset ) {
00177 $this->mOffset = $offset;
00178 }
00182 function setLimit( $limit ) {
00183 $this->mLimit = $limit;
00184 }
00185
00190 function extractResultInfo( $offset, $limit, ResultWrapper $res ) {
00191 $numRows = $res->numRows();
00192 if ( $numRows ) {
00193 $row = $res->fetchRow();
00194 $firstIndex = $row[$this->mIndexField];
00195
00196 # Discard the extra result row if there is one
00197 if ( $numRows > $this->mLimit && $numRows > 1 ) {
00198 $res->seek( $numRows - 1 );
00199 $this->mPastTheEndRow = $res->fetchObject();
00200 $indexField = $this->mIndexField;
00201 $this->mPastTheEndIndex = $this->mPastTheEndRow->$indexField;
00202 $res->seek( $numRows - 2 );
00203 $row = $res->fetchRow();
00204 $lastIndex = $row[$this->mIndexField];
00205 } else {
00206 $this->mPastTheEndRow = null;
00207 # Setting indexes to an empty string means that they will be
00208 # omitted if they would otherwise appear in URLs. It just so
00209 # happens that this is the right thing to do in the standard
00210 # UI, in all the relevant cases.
00211 $this->mPastTheEndIndex = '';
00212 $res->seek( $numRows - 1 );
00213 $row = $res->fetchRow();
00214 $lastIndex = $row[$this->mIndexField];
00215 }
00216 } else {
00217 $firstIndex = '';
00218 $lastIndex = '';
00219 $this->mPastTheEndRow = null;
00220 $this->mPastTheEndIndex = '';
00221 }
00222
00223 if ( $this->mIsBackwards ) {
00224 $this->mIsFirst = ( $numRows < $limit );
00225 $this->mIsLast = ( $offset == '' );
00226 $this->mLastShown = $firstIndex;
00227 $this->mFirstShown = $lastIndex;
00228 } else {
00229 $this->mIsFirst = ( $offset == '' );
00230 $this->mIsLast = ( $numRows < $limit );
00231 $this->mLastShown = $lastIndex;
00232 $this->mFirstShown = $firstIndex;
00233 }
00234 }
00235
00239 function getSqlComment() {
00240 return get_class( $this );
00241 }
00242
00252 function reallyDoQuery( $offset, $limit, $descending ) {
00253 $fname = __METHOD__ . ' (' . $this->getSqlComment() . ')';
00254 $info = $this->getQueryInfo();
00255 $tables = $info['tables'];
00256 $fields = $info['fields'];
00257 $conds = isset( $info['conds'] ) ? $info['conds'] : array();
00258 $options = isset( $info['options'] ) ? $info['options'] : array();
00259 $join_conds = isset( $info['join_conds'] ) ? $info['join_conds'] : array();
00260 if ( $descending ) {
00261 $options['ORDER BY'] = $this->mIndexField;
00262 $operator = '>';
00263 } else {
00264 $options['ORDER BY'] = $this->mIndexField . ' DESC';
00265 $operator = '<';
00266 }
00267 if ( $offset != '' ) {
00268 $conds[] = $this->mIndexField . $operator . $this->mDb->addQuotes( $offset );
00269 }
00270 $options['LIMIT'] = intval( $limit );
00271 $res = $this->mDb->select( $tables, $fields, $conds, $fname, $options, $join_conds );
00272 return new ResultWrapper( $this->mDb, $res );
00273 }
00274
00280 protected function preprocessResults( $result ) {}
00281
00286 function getBody() {
00287 if ( !$this->mQueryDone ) {
00288 $this->doQuery();
00289 }
00290 # Don't use any extra rows returned by the query
00291 $numRows = min( $this->mResult->numRows(), $this->mLimit );
00292
00293 $s = $this->getStartBody();
00294 if ( $numRows ) {
00295 if ( $this->mIsBackwards ) {
00296 for ( $i = $numRows - 1; $i >= 0; $i-- ) {
00297 $this->mResult->seek( $i );
00298 $row = $this->mResult->fetchObject();
00299 $s .= $this->formatRow( $row );
00300 }
00301 } else {
00302 $this->mResult->seek( 0 );
00303 for ( $i = 0; $i < $numRows; $i++ ) {
00304 $row = $this->mResult->fetchObject();
00305 $s .= $this->formatRow( $row );
00306 }
00307 }
00308 } else {
00309 $s .= $this->getEmptyBody();
00310 }
00311 $s .= $this->getEndBody();
00312 return $s;
00313 }
00314
00318 function makeLink($text, $query = null, $type=null) {
00319 if ( $query === null ) {
00320 return $text;
00321 }
00322
00323 $attrs = array();
00324 if( in_array( $type, array( 'first', 'prev', 'next', 'last' ) ) ) {
00325 # HTML5 rel attributes
00326 $attrs['rel'] = $type;
00327 }
00328
00329 if( $type ) {
00330 $attrs['class'] = "mw-{$type}link";
00331 }
00332 return $this->getSkin()->link(
00333 $this->getTitle(),
00334 $text,
00335 $attrs,
00336 $query + $this->getDefaultQuery(),
00337 array( 'noclasses', 'known' )
00338 );
00339 }
00340
00345 function getStartBody() {
00346 return '';
00347 }
00348
00352 function getEndBody() {
00353 return '';
00354 }
00355
00360 function getEmptyBody() {
00361 return '';
00362 }
00363
00368 function getTitle() {
00369 return $GLOBALS['wgTitle'];
00370 }
00371
00375 function getSkin() {
00376 if ( !isset( $this->mSkin ) ) {
00377 global $wgUser;
00378 $this->mSkin = $wgUser->getSkin();
00379 }
00380 return $this->mSkin;
00381 }
00382
00388 function getDefaultQuery() {
00389 if ( !isset( $this->mDefaultQuery ) ) {
00390 $this->mDefaultQuery = $_GET;
00391 unset( $this->mDefaultQuery['title'] );
00392 unset( $this->mDefaultQuery['dir'] );
00393 unset( $this->mDefaultQuery['offset'] );
00394 unset( $this->mDefaultQuery['limit'] );
00395 unset( $this->mDefaultQuery['order'] );
00396 unset( $this->mDefaultQuery['month'] );
00397 unset( $this->mDefaultQuery['year'] );
00398 }
00399 return $this->mDefaultQuery;
00400 }
00401
00405 function getNumRows() {
00406 if ( !$this->mQueryDone ) {
00407 $this->doQuery();
00408 }
00409 return $this->mResult->numRows();
00410 }
00411
00415 function getPagingQueries() {
00416 if ( !$this->mQueryDone ) {
00417 $this->doQuery();
00418 }
00419
00420 # Don't announce the limit everywhere if it's the default
00421 $urlLimit = $this->mLimit == $this->mDefaultLimit ? '' : $this->mLimit;
00422
00423 if ( $this->mIsFirst ) {
00424 $prev = false;
00425 $first = false;
00426 } else {
00427 $prev = array(
00428 'dir' => 'prev',
00429 'offset' => $this->mFirstShown,
00430 'limit' => $urlLimit
00431 );
00432 $first = array( 'limit' => $urlLimit );
00433 }
00434 if ( $this->mIsLast ) {
00435 $next = false;
00436 $last = false;
00437 } else {
00438 $next = array( 'offset' => $this->mLastShown, 'limit' => $urlLimit );
00439 $last = array( 'dir' => 'prev', 'limit' => $urlLimit );
00440 }
00441 return array(
00442 'prev' => $prev,
00443 'next' => $next,
00444 'first' => $first,
00445 'last' => $last
00446 );
00447 }
00448
00449 function isNavigationBarShown() {
00450 if ( !$this->mQueryDone ) {
00451 $this->doQuery();
00452 }
00453
00454 return !($this->mIsFirst && $this->mIsLast);
00455 }
00456
00463 function getPagingLinks( $linkTexts, $disabledTexts = array() ) {
00464 $queries = $this->getPagingQueries();
00465 $links = array();
00466 foreach ( $queries as $type => $query ) {
00467 if ( $query !== false ) {
00468 $links[$type] = $this->makeLink(
00469 $linkTexts[$type],
00470 $queries[$type],
00471 $type
00472 );
00473 } elseif ( isset( $disabledTexts[$type] ) ) {
00474 $links[$type] = $disabledTexts[$type];
00475 } else {
00476 $links[$type] = $linkTexts[$type];
00477 }
00478 }
00479 return $links;
00480 }
00481
00482 function getLimitLinks() {
00483 global $wgLang;
00484 $links = array();
00485 if ( $this->mIsBackwards ) {
00486 $offset = $this->mPastTheEndIndex;
00487 } else {
00488 $offset = $this->mOffset;
00489 }
00490 foreach ( $this->mLimitsShown as $limit ) {
00491 $links[] = $this->makeLink(
00492 $wgLang->formatNum( $limit ),
00493 array( 'offset' => $offset, 'limit' => $limit ),
00494 'num'
00495 );
00496 }
00497 return $links;
00498 }
00499
00505 abstract function formatRow( $row );
00506
00517 abstract function getQueryInfo();
00518
00529 abstract function getIndexField();
00530
00548 protected function getDefaultDirections() { return false; }
00549 }
00550
00551
00556 abstract class AlphabeticPager extends IndexPager {
00561 function getNavigationBar() {
00562 global $wgLang;
00563
00564 if ( !$this->isNavigationBarShown() ) return '';
00565
00566 if( isset( $this->mNavigationBar ) ) {
00567 return $this->mNavigationBar;
00568 }
00569
00570 $opts = array( 'parsemag', 'escapenoentities' );
00571 $linkTexts = array(
00572 'prev' => wfMsgExt(
00573 'prevn',
00574 $opts,
00575 $wgLang->formatNum( $this->mLimit )
00576 ),
00577 'next' => wfMsgExt(
00578 'nextn',
00579 $opts,
00580 $wgLang->formatNum($this->mLimit )
00581 ),
00582 'first' => wfMsgExt( 'page_first', $opts ),
00583 'last' => wfMsgExt( 'page_last', $opts )
00584 );
00585
00586 $pagingLinks = $this->getPagingLinks( $linkTexts );
00587 $limitLinks = $this->getLimitLinks();
00588 $limits = $wgLang->pipeList( $limitLinks );
00589
00590 $this->mNavigationBar =
00591 "(" . $wgLang->pipeList(
00592 array( $pagingLinks['first'],
00593 $pagingLinks['last'] )
00594 ) . ") " .
00595 wfMsgHtml( 'viewprevnext', $pagingLinks['prev'],
00596 $pagingLinks['next'], $limits );
00597
00598 if( !is_array( $this->getIndexField() ) ) {
00599 # Early return to avoid undue nesting
00600 return $this->mNavigationBar;
00601 }
00602
00603 $extra = '';
00604 $first = true;
00605 $msgs = $this->getOrderTypeMessages();
00606 foreach( array_keys( $msgs ) as $order ) {
00607 if( $first ) {
00608 $first = false;
00609 } else {
00610 $extra .= wfMsgExt( 'pipe-separator' , 'escapenoentities' );
00611 }
00612
00613 if( $order == $this->mOrderType ) {
00614 $extra .= wfMsgHTML( $msgs[$order] );
00615 } else {
00616 $extra .= $this->makeLink(
00617 wfMsgHTML( $msgs[$order] ),
00618 array( 'order' => $order )
00619 );
00620 }
00621 }
00622
00623 if( $extra !== '' ) {
00624 $this->mNavigationBar .= " ($extra)";
00625 }
00626
00627 return $this->mNavigationBar;
00628 }
00629
00637 protected function getOrderTypeMessages() {
00638 return null;
00639 }
00640 }
00641
00646 abstract class ReverseChronologicalPager extends IndexPager {
00647 public $mDefaultDirection = true;
00648 public $mYear;
00649 public $mMonth;
00650
00651 function __construct() {
00652 parent::__construct();
00653 }
00654
00655 function getNavigationBar() {
00656 global $wgLang;
00657
00658 if ( !$this->isNavigationBarShown() ) return '';
00659
00660 if ( isset( $this->mNavigationBar ) ) {
00661 return $this->mNavigationBar;
00662 }
00663 $nicenumber = $wgLang->formatNum( $this->mLimit );
00664 $linkTexts = array(
00665 'prev' => wfMsgExt(
00666 'pager-newer-n',
00667 array( 'parsemag', 'escape' ),
00668 $nicenumber
00669 ),
00670 'next' => wfMsgExt(
00671 'pager-older-n',
00672 array( 'parsemag', 'escape' ),
00673 $nicenumber
00674 ),
00675 'first' => wfMsgHtml( 'histlast' ),
00676 'last' => wfMsgHtml( 'histfirst' )
00677 );
00678
00679 $pagingLinks = $this->getPagingLinks( $linkTexts );
00680 $limitLinks = $this->getLimitLinks();
00681 $limits = $wgLang->pipeList( $limitLinks );
00682
00683 $this->mNavigationBar = "({$pagingLinks['first']}" .
00684 wfMsgExt( 'pipe-separator' , 'escapenoentities' ) .
00685 "{$pagingLinks['last']}) " .
00686 wfMsgHTML(
00687 'viewprevnext',
00688 $pagingLinks['prev'], $pagingLinks['next'],
00689 $limits
00690 );
00691 return $this->mNavigationBar;
00692 }
00693
00694 function getDateCond( $year, $month ) {
00695 $year = intval($year);
00696 $month = intval($month);
00697
00698 $this->mYear = $year > 0 ? $year : false;
00699 $this->mMonth = ($month > 0 && $month < 13) ? $month : false;
00700
00701
00702
00703
00704
00705 if ( !$this->mYear && !$this->mMonth ) {
00706 return;
00707 }
00708 if ( $this->mYear ) {
00709 $year = $this->mYear;
00710 } else {
00711
00712 $year = gmdate( 'Y' );
00713
00714 if( $this->mMonth > gmdate( 'n' ) ) {
00715 $year--;
00716 }
00717 }
00718 if ( $this->mMonth ) {
00719 $month = $this->mMonth + 1;
00720
00721 if ($month > 12) {
00722 $month = 1;
00723 $year++;
00724 }
00725 } else {
00726
00727 $month = 1;
00728 $year++;
00729 }
00730
00731 if ( $year > 2032 ) {
00732 $year = 2032;
00733 }
00734 $ymd = (int)sprintf( "%04d%02d01", $year, $month );
00735 if ( $ymd > 20320101 ) {
00736 $ymd = 20320101;
00737 }
00738 $this->mOffset = $this->mDb->timestamp( "${ymd}000000" );
00739 }
00740 }
00741
00746 abstract class TablePager extends IndexPager {
00747 var $mSort;
00748 var $mCurrentRow;
00749
00750 function __construct() {
00751 global $wgRequest;
00752 $this->mSort = $wgRequest->getText( 'sort' );
00753 if ( !array_key_exists( $this->mSort, $this->getFieldNames() ) ) {
00754 $this->mSort = $this->getDefaultSort();
00755 }
00756 if ( $wgRequest->getBool( 'asc' ) ) {
00757 $this->mDefaultDirection = false;
00758 } elseif ( $wgRequest->getBool( 'desc' ) ) {
00759 $this->mDefaultDirection = true;
00760 }
00761
00762 parent::__construct();
00763 }
00764
00765 function getStartBody() {
00766 global $wgStylePath;
00767 $tableClass = htmlspecialchars( $this->getTableClass() );
00768 $sortClass = htmlspecialchars( $this->getSortHeaderClass() );
00769
00770 $s = "<table border='1' class=\"$tableClass\"><thead><tr>\n";
00771 $fields = $this->getFieldNames();
00772
00773 # Make table header
00774 foreach ( $fields as $field => $name ) {
00775 if ( strval( $name ) == '' ) {
00776 $s .= "<th> </th>\n";
00777 } elseif ( $this->isFieldSortable( $field ) ) {
00778 $query = array( 'sort' => $field, 'limit' => $this->mLimit );
00779 if ( $field == $this->mSort ) {
00780 # This is the sorted column
00781 # Prepare a link that goes in the other sort order
00782 if ( $this->mDefaultDirection ) {
00783 # Descending
00784 $image = 'Arr_u.png';
00785 $query['asc'] = '1';
00786 $query['desc'] = '';
00787 $alt = htmlspecialchars( wfMsg( 'descending_abbrev' ) );
00788 } else {
00789 # Ascending
00790 $image = 'Arr_d.png';
00791 $query['asc'] = '';
00792 $query['desc'] = '1';
00793 $alt = htmlspecialchars( wfMsg( 'ascending_abbrev' ) );
00794 }
00795 $image = htmlspecialchars( "$wgStylePath/common/images/$image" );
00796 $link = $this->makeLink(
00797 "<img width=\"12\" height=\"12\" alt=\"$alt\" src=\"$image\" />" .
00798 htmlspecialchars( $name ), $query );
00799 $s .= "<th class=\"$sortClass\">$link</th>\n";
00800 } else {
00801 $s .= '<th>' . $this->makeLink( htmlspecialchars( $name ), $query ) . "</th>\n";
00802 }
00803 } else {
00804 $s .= '<th>' . htmlspecialchars( $name ) . "</th>\n";
00805 }
00806 }
00807 $s .= "</tr></thead><tbody>\n";
00808 return $s;
00809 }
00810
00811 function getEndBody() {
00812 return "</tbody></table>\n";
00813 }
00814
00815 function getEmptyBody() {
00816 $colspan = count( $this->getFieldNames() );
00817 $msgEmpty = wfMsgHtml( 'table_pager_empty' );
00818 return "<tr><td colspan=\"$colspan\">$msgEmpty</td></tr>\n";
00819 }
00820
00821 function formatRow( $row ) {
00822 $this->mCurrentRow = $row; # In case formatValue etc need to know
00823 $s = Xml::openElement( 'tr', $this->getRowAttrs($row) );
00824 $fieldNames = $this->getFieldNames();
00825 foreach ( $fieldNames as $field => $name ) {
00826 $value = isset( $row->$field ) ? $row->$field : null;
00827 $formatted = strval( $this->formatValue( $field, $value ) );
00828 if ( $formatted == '' ) {
00829 $formatted = ' ';
00830 }
00831 $s .= Xml::tags( 'td', $this->getCellAttrs( $field, $value ), $formatted );
00832 }
00833 $s .= "</tr>\n";
00834 return $s;
00835 }
00836
00841 function getRowClass( $row ) {
00842 return '';
00843 }
00844
00850 function getRowAttrs( $row ) {
00851 return array( 'class' => $this->getRowClass( $row ) );
00852 }
00853
00862 function getCellAttrs( $field, $value ) {
00863 return array( 'class' => 'TablePager_col_' . $field );
00864 }
00865
00866 function getIndexField() {
00867 return $this->mSort;
00868 }
00869
00870 function getTableClass() {
00871 return 'TablePager';
00872 }
00873
00874 function getNavClass() {
00875 return 'TablePager_nav';
00876 }
00877
00878 function getSortHeaderClass() {
00879 return 'TablePager_sort';
00880 }
00881
00885 function getNavigationBar() {
00886 global $wgStylePath, $wgContLang;
00887
00888 if ( !$this->isNavigationBarShown() ) return '';
00889
00890 $path = "$wgStylePath/common/images";
00891 $labels = array(
00892 'first' => 'table_pager_first',
00893 'prev' => 'table_pager_prev',
00894 'next' => 'table_pager_next',
00895 'last' => 'table_pager_last',
00896 );
00897 $images = array(
00898 'first' => 'arrow_first_25.png',
00899 'prev' => 'arrow_left_25.png',
00900 'next' => 'arrow_right_25.png',
00901 'last' => 'arrow_last_25.png',
00902 );
00903 $disabledImages = array(
00904 'first' => 'arrow_disabled_first_25.png',
00905 'prev' => 'arrow_disabled_left_25.png',
00906 'next' => 'arrow_disabled_right_25.png',
00907 'last' => 'arrow_disabled_last_25.png',
00908 );
00909 if( $wgContLang->isRTL() ) {
00910 $keys = array_keys( $labels );
00911 $images = array_combine( $keys, array_reverse( $images ) );
00912 $disabledImages = array_combine( $keys, array_reverse( $disabledImages ) );
00913 }
00914
00915 $linkTexts = array();
00916 $disabledTexts = array();
00917 foreach ( $labels as $type => $label ) {
00918 $msgLabel = wfMsgHtml( $label );
00919 $linkTexts[$type] = "<img src=\"$path/{$images[$type]}\" alt=\"$msgLabel\"/><br />$msgLabel";
00920 $disabledTexts[$type] = "<img src=\"$path/{$disabledImages[$type]}\" alt=\"$msgLabel\"/><br />$msgLabel";
00921 }
00922 $links = $this->getPagingLinks( $linkTexts, $disabledTexts );
00923
00924 $navClass = htmlspecialchars( $this->getNavClass() );
00925 $s = "<table class=\"$navClass\" align=\"center\" cellpadding=\"3\"><tr>\n";
00926 $cellAttrs = 'valign="top" align="center" width="' . 100 / count( $links ) . '%"';
00927 foreach ( $labels as $type => $label ) {
00928 $s .= "<td $cellAttrs>{$links[$type]}</td>\n";
00929 }
00930 $s .= "</tr></table>\n";
00931 return $s;
00932 }
00933
00937 function getLimitSelect() {
00938 global $wgLang;
00939 $s = "<select name=\"limit\">";
00940 foreach ( $this->mLimitsShown as $key => $value ) {
00941 # The pair is either $index => $limit, in which case the $value
00942 # will be numeric, or $limit => $text, in which case the $value
00943 # will be a string.
00944 if( is_int( $value ) ){
00945 $limit = $value;
00946 $text = $wgLang->formatNum( $limit );
00947 } else {
00948 $limit = $key;
00949 $text = $value;
00950 }
00951 $selected = ( $limit == $this->mLimit ? 'selected="selected"' : '' );
00952 $s .= "<option value=\"$limit\" $selected>$text</option>\n";
00953 }
00954 $s .= "</select>";
00955 return $s;
00956 }
00957
00963 function getHiddenFields( $blacklist = array() ) {
00964 $blacklist = (array)$blacklist;
00965 $query = $_GET;
00966 foreach ( $blacklist as $name ) {
00967 unset( $query[$name] );
00968 }
00969 $s = '';
00970 foreach ( $query as $name => $value ) {
00971 $encName = htmlspecialchars( $name );
00972 $encValue = htmlspecialchars( $value );
00973 $s .= "<input type=\"hidden\" name=\"$encName\" value=\"$encValue\"/>\n";
00974 }
00975 return $s;
00976 }
00977
00981 function getLimitForm() {
00982 global $wgScript;
00983
00984 # Make the select with some explanatory text
00985 $msgSubmit = wfMsgHtml( 'table_pager_limit_submit' );
00986 return
00987 Xml::openElement(
00988 'form',
00989 array(
00990 'method' => 'get',
00991 'action' => $wgScript
00992 )
00993 ) . "\n" .
00994 wfMsgHtml( 'table_pager_limit', $this->getLimitSelect() ) .
00995 "\n<input type=\"submit\" value=\"$msgSubmit\"/>\n" .
00996 $this->getHiddenFields( array( 'limit' ) ) .
00997 "</form>\n";
00998 }
00999
01006 abstract function isFieldSortable( $field );
01007
01018 abstract function formatValue( $name, $value );
01019
01023 abstract function getDefaultSort();
01024
01030 abstract function getFieldNames();
01031 }