diff options
author | jenkins-bot <jenkins-bot@gerrit.wikimedia.org> | 2024-05-09 19:39:16 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@wikimedia.org> | 2024-05-09 19:39:16 +0000 |
commit | 04787125e8c7f9cef82b3f6a1430213039e2a9f1 (patch) | |
tree | 4a303099e8dcd890d97465137b4e6664ce3cad29 /includes/pager | |
parent | 5063676128b3e3215fd2d873cc404c18b117436e (diff) | |
parent | e6fb3df2a639ca95afdec2255f1da63187ba71c6 (diff) | |
download | mediawikicore-04787125e8c7f9cef82b3f6a1430213039e2a9f1.tar.gz mediawikicore-04787125e8c7f9cef82b3f6a1430213039e2a9f1.zip |
Merge "Revert "Add ContributionsPager, an abstract parent for ContribsPager""
Diffstat (limited to 'includes/pager')
-rw-r--r-- | includes/pager/ContributionsPager.php | 789 |
1 files changed, 0 insertions, 789 deletions
diff --git a/includes/pager/ContributionsPager.php b/includes/pager/ContributionsPager.php deleted file mode 100644 index 2b7192dae6ce..000000000000 --- a/includes/pager/ContributionsPager.php +++ /dev/null @@ -1,789 +0,0 @@ -<?php -/** - * 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 - * @ingroup Pager - */ - -namespace MediaWiki\Pager; - -use ChangesList; -use ChangeTags; -use HtmlArmor; -use InvalidArgumentException; -use MapCacheLRU; -use MediaWiki\Cache\LinkBatchFactory; -use MediaWiki\CommentFormatter\CommentFormatter; -use MediaWiki\Context\IContextSource; -use MediaWiki\HookContainer\HookContainer; -use MediaWiki\HookContainer\HookRunner; -use MediaWiki\Html\Html; -use MediaWiki\Html\TemplateParser; -use MediaWiki\Linker\Linker; -use MediaWiki\Linker\LinkRenderer; -use MediaWiki\MainConfigNames; -use MediaWiki\Parser\Sanitizer; -use MediaWiki\Revision\RevisionRecord; -use MediaWiki\Revision\RevisionStore; -use MediaWiki\Title\NamespaceInfo; -use MediaWiki\Title\Title; -use MediaWiki\User\UserFactory; -use MediaWiki\User\UserIdentity; -use MediaWiki\User\UserRigorOptions; -use stdClass; -use Wikimedia\Rdbms\FakeResultWrapper; -use Wikimedia\Rdbms\IResultWrapper; - -/** - * Pager for Special:Contributions - * @ingroup Pager - */ -abstract class ContributionsPager extends RangeChronologicalPager { - - public $mGroupByDate = true; - - /** - * @var string[] Local cache for escaped messages - */ - private $messages; - - /** - * @var string User name, or a string describing an IP address range - */ - protected $target; - - /** - * @var string|int A single namespace number, or an empty string for all namespaces - */ - private $namespace; - - /** - * @var string[]|false Name of tag to filter, or false to ignore tags - */ - private $tagFilter; - - /** - * @var bool Set to true to invert the tag selection - */ - private $tagInvert; - - /** - * @var bool Set to true to invert the namespace selection - */ - private $nsInvert; - - /** - * @var bool Set to true to show both the subject and talk namespace, no matter which got - * selected - */ - private $associated; - - /** - * @var bool Set to true to show only deleted revisions - */ - private $deletedOnly; - - /** - * @var bool Set to true to show only latest (a.k.a. current) revisions - */ - private $topOnly; - - /** - * @var bool Set to true to show only new pages - */ - private $newOnly; - - /** - * @var bool Set to true to hide edits marked as minor by the user - */ - private $hideMinor; - - /** - * @var bool Set to true to only include mediawiki revisions. - * (restricts extensions from executing additional queries to include their own contributions) - */ - private $revisionsOnly; - - private $preventClickjacking = false; - - /** - * @var array - */ - private $mParentLens; - - /** @var UserIdentity */ - protected $targetUser; - - private TemplateParser $templateParser; - private CommentFormatter $commentFormatter; - private HookRunner $hookRunner; - private LinkBatchFactory $linkBatchFactory; - private NamespaceInfo $namespaceInfo; - protected RevisionStore $revisionStore; - - /** @var string[] */ - private $formattedComments = []; - - /** @var RevisionRecord[] Cached revisions by ID */ - private $revisions = []; - - /** @var MapCacheLRU */ - private $tagsCache; - - /** - * @param LinkRenderer $linkRenderer - * @param LinkBatchFactory $linkBatchFactory - * @param HookContainer $hookContainer - * @param RevisionStore $revisionStore - * @param NamespaceInfo $namespaceInfo - * @param CommentFormatter $commentFormatter - * @param UserFactory $userFactory - * @param IContextSource $context - * @param array $options - * @param UserIdentity|null $targetUser - */ - public function __construct( - LinkRenderer $linkRenderer, - LinkBatchFactory $linkBatchFactory, - HookContainer $hookContainer, - RevisionStore $revisionStore, - NamespaceInfo $namespaceInfo, - CommentFormatter $commentFormatter, - UserFactory $userFactory, - IContextSource $context, - array $options, - ?UserIdentity $targetUser - ) { - // Set ->target before calling parent::__construct() so - // parent can call $this->getIndexField() and get the right result. Set - // the rest too just to keep things simple. - if ( $targetUser ) { - $this->target = $options['target'] ?? $targetUser->getName(); - $this->targetUser = $targetUser; - } else { - // Use target option - // It's possible for the target to be empty. This is used by - // ContribsPagerTest and does not cause newFromName() to return - // false. It's probably not used by any production code. - $this->target = $options['target'] ?? ''; - // @phan-suppress-next-line PhanPossiblyNullTypeMismatchProperty RIGOR_NONE never returns null - $this->targetUser = $userFactory->newFromName( - $this->target, UserRigorOptions::RIGOR_NONE - ); - if ( !$this->targetUser ) { - // This can happen if the target contained "#". Callers - // typically pass user input through title normalization to - // avoid it. - throw new InvalidArgumentException( __METHOD__ . ': the user name is too ' . - 'broken to use even with validation disabled.' ); - } - } - - $this->namespace = $options['namespace'] ?? ''; - $this->tagFilter = $options['tagfilter'] ?? false; - $this->tagInvert = $options['tagInvert'] ?? false; - $this->nsInvert = $options['nsInvert'] ?? false; - $this->associated = $options['associated'] ?? false; - - $this->deletedOnly = !empty( $options['deletedOnly'] ); - $this->topOnly = !empty( $options['topOnly'] ); - $this->newOnly = !empty( $options['newOnly'] ); - $this->hideMinor = !empty( $options['hideMinor'] ); - $this->revisionsOnly = !empty( $options['revisionsOnly'] ); - - parent::__construct( $context, $linkRenderer ); - - $msgs = [ - 'diff', - 'hist', - 'pipe-separator', - 'uctop', - 'changeslist-nocomment', - ]; - - foreach ( $msgs as $msg ) { - $this->messages[$msg] = $this->msg( $msg )->escaped(); - } - - // Date filtering: use timestamp if available - $startTimestamp = ''; - $endTimestamp = ''; - if ( isset( $options['start'] ) && $options['start'] ) { - $startTimestamp = $options['start'] . ' 00:00:00'; - } - if ( isset( $options['end'] ) && $options['end'] ) { - $endTimestamp = $options['end'] . ' 23:59:59'; - } - $this->getDateRangeCond( $startTimestamp, $endTimestamp ); - - $this->templateParser = new TemplateParser(); - $this->linkBatchFactory = $linkBatchFactory; - $this->hookRunner = new HookRunner( $hookContainer ); - $this->revisionStore = $revisionStore; - $this->namespaceInfo = $namespaceInfo; - $this->commentFormatter = $commentFormatter; - $this->tagsCache = new MapCacheLRU( 50 ); - } - - public function getDefaultQuery() { - $query = parent::getDefaultQuery(); - $query['target'] = $this->target; - - return $query; - } - - /** - * This method basically executes the exact same code as the parent class, though with - * a hook added, to allow extensions to add additional queries. - * - * @param string $offset Index offset, inclusive - * @param int $limit Exact query limit - * @param bool $order IndexPager::QUERY_ASCENDING or IndexPager::QUERY_DESCENDING - * @return IResultWrapper - */ - public function reallyDoQuery( $offset, $limit, $order ) { - [ $tables, $fields, $conds, $fname, $options, $join_conds ] = $this->buildQueryInfo( - $offset, - $limit, - $order - ); - - $options['MAX_EXECUTION_TIME'] = - $this->getConfig()->get( MainConfigNames::MaxExecutionTimeForExpensiveQueries ); - /* - * This hook will allow extensions to add in additional queries, so they can get their data - * in My Contributions as well. Extensions should append their results to the $data array. - * - * Extension queries have to implement the navbar requirement as well. They should - * - have a column aliased as $pager->getIndexField() - * - have LIMIT set - * - have a WHERE-clause that compares the $pager->getIndexField()-equivalent column to the offset - * - have the ORDER BY specified based upon the details provided by the navbar - * - * See includes/Pager.php buildQueryInfo() method on how to build LIMIT, WHERE & ORDER BY - * - * &$data: an array of results of all contribs queries - * $pager: the ContribsPager object hooked into - * $offset: see phpdoc above - * $limit: see phpdoc above - * $descending: see phpdoc above - */ - $dbr = $this->getDatabase(); - $data = [ $dbr->newSelectQueryBuilder() - ->tables( is_array( $tables ) ? $tables : [ $tables ] ) - ->fields( $fields ) - ->conds( $conds ) - ->caller( $fname ) - ->options( $options ) - ->joinConds( $join_conds ) - ->setMaxExecutionTime( $this->getConfig()->get( MainConfigNames::MaxExecutionTimeForExpensiveQueries ) ) - ->fetchResultSet() ]; - if ( !$this->revisionsOnly ) { - // TODO: Range offsets are fairly important and all handlers should take care of it. - // If this hook will be replaced (e.g. unified with the DeletedContribsPager one), - // please consider passing [ $this->endOffset, $this->startOffset ] to it (T167577). - $this->hookRunner->onContribsPager__reallyDoQuery( - $data, $this, $offset, $limit, $order ); - } - - $result = []; - - // loop all results and collect them in an array - foreach ( $data as $query ) { - foreach ( $query as $i => $row ) { - // If the query results are in descending order, the indexes must also be in descending order - $index = $order === self::QUERY_ASCENDING ? $i : $limit - 1 - $i; - // Left-pad with zeroes, because these values will be sorted as strings - $index = str_pad( (string)$index, strlen( (string)$limit ), '0', STR_PAD_LEFT ); - // use index column as key, allowing us to easily sort in PHP - $result[$row->{$this->getIndexField()} . "-$index"] = $row; - } - } - - // sort results - if ( $order === self::QUERY_ASCENDING ) { - ksort( $result ); - } else { - krsort( $result ); - } - - // enforce limit - $result = array_slice( $result, 0, $limit ); - - // get rid of array keys - $result = array_values( $result ); - - return new FakeResultWrapper( $result ); - } - - /** - * Get queryInfo for the main query selecting revisions, not including - * filtering on namespace, date, etc. - * - * @return array - */ - abstract protected function getRevisionQuery(); - - public function getQueryInfo() { - $queryInfo = $this->getRevisionQuery(); - - if ( $this->deletedOnly ) { - $queryInfo['conds'][] = 'rev_deleted != 0'; - } - - if ( $this->topOnly ) { - $queryInfo['conds'][] = 'rev_id = page_latest'; - } - - if ( $this->newOnly ) { - $queryInfo['conds'][] = 'rev_parent_id = 0'; - } - - if ( $this->hideMinor ) { - $queryInfo['conds'][] = 'rev_minor_edit = 0'; - } - - $queryInfo['conds'] = array_merge( $queryInfo['conds'], $this->getNamespaceCond() ); - - // Paranoia: avoid brute force searches (T19342) - $dbr = $this->getDatabase(); - if ( !$this->getAuthority()->isAllowed( 'deletedhistory' ) ) { - $queryInfo['conds'][] = $dbr->bitAnd( - 'rev_deleted', RevisionRecord::DELETED_USER - ) . ' = 0'; - } elseif ( !$this->getAuthority()->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { - $queryInfo['conds'][] = $dbr->bitAnd( - 'rev_deleted', RevisionRecord::SUPPRESSED_USER - ) . ' != ' . RevisionRecord::SUPPRESSED_USER; - } - - // $this->getIndexField() must be in the result rows, as reallyDoQuery() tries to access it. - $indexField = $this->getIndexField(); - if ( $indexField !== 'rev_timestamp' ) { - $queryInfo['fields'][] = $indexField; - } - - ChangeTags::modifyDisplayQuery( - $queryInfo['tables'], - $queryInfo['fields'], - $queryInfo['conds'], - $queryInfo['join_conds'], - $queryInfo['options'], - $this->tagFilter, - $this->tagInvert, - ); - - $this->hookRunner->onContribsPager__getQueryInfo( $this, $queryInfo ); - - return $queryInfo; - } - - protected function getNamespaceCond() { - if ( $this->namespace !== '' ) { - $dbr = $this->getDatabase(); - $selectedNS = $dbr->addQuotes( $this->namespace ); - $eq_op = $this->nsInvert ? '!=' : '='; - $bool_op = $this->nsInvert ? 'AND' : 'OR'; - - if ( !$this->associated ) { - return [ "page_namespace $eq_op $selectedNS" ]; - } - - $associatedNS = $dbr->addQuotes( $this->namespaceInfo->getAssociated( $this->namespace ) ); - - return [ - "page_namespace $eq_op $selectedNS " . - $bool_op . - " page_namespace $eq_op $associatedNS" - ]; - } - - return []; - } - - /** - * @return false|string[] - */ - public function getTagFilter() { - return $this->tagFilter; - } - - /** - * @return bool - */ - public function getTagInvert() { - return $this->tagInvert; - } - - /** - * @return string - */ - public function getTarget() { - return $this->target; - } - - /** - * @return bool - */ - public function isNewOnly() { - return $this->newOnly; - } - - /** - * @return int|string - */ - public function getNamespace() { - return $this->namespace; - } - - protected function doBatchLookups() { - # Do a link batch query - $this->mResult->seek( 0 ); - $parentRevIds = []; - $this->mParentLens = []; - $revisions = []; - $linkBatch = $this->linkBatchFactory->newLinkBatch(); - # Give some pointers to make (last) links - foreach ( $this->mResult as $row ) { - if ( isset( $row->rev_parent_id ) && $row->rev_parent_id ) { - $parentRevIds[] = (int)$row->rev_parent_id; - } - if ( $this->revisionStore->isRevisionRow( $row ) ) { - $this->mParentLens[(int)$row->rev_id] = $row->rev_len; - if ( $this->target !== $row->rev_user_text ) { - // If the target does not match the author, batch the author's talk page - $linkBatch->add( NS_USER_TALK, $row->rev_user_text ); - } - $linkBatch->add( $row->page_namespace, $row->page_title ); - $revisions[$row->rev_id] = $this->revisionStore->newRevisionFromRow( $row ); - } - } - # Fetch rev_len for revisions not already scanned above - $this->mParentLens += $this->revisionStore->getRevisionSizes( - array_diff( $parentRevIds, array_keys( $this->mParentLens ) ) - ); - $linkBatch->execute(); - - $this->formattedComments = $this->commentFormatter->createRevisionBatch() - ->authority( $this->getAuthority() ) - ->revisions( $revisions ) - ->hideIfDeleted() - ->execute(); - - # For performance, save the revision objects for later. - # The array is indexed by rev_id. doBatchLookups() may be called - # multiple times with different results, so merge the revisions array, - # ignoring any duplicates. - $this->revisions += $revisions; - } - - /** - * @inheritDoc - */ - protected function getStartBody() { - return "<section class='mw-pager-body'>\n"; - } - - /** - * @inheritDoc - */ - protected function getEndBody() { - return "</section>\n"; - } - - /** - * If the object looks like a revision row, or corresponds to a previously - * cached revision, return the RevisionRecord. Otherwise, return null. - * - * @since 1.35 - * - * @param mixed $row - * @param Title|null $title - * @return RevisionRecord|null - */ - public function tryCreatingRevisionRecord( $row, $title = null ) { - if ( $row instanceof stdClass && isset( $row->rev_id ) - && isset( $this->revisions[$row->rev_id] ) - ) { - return $this->revisions[$row->rev_id]; - } elseif ( $this->revisionStore->isRevisionRow( $row ) ) { - return $this->revisionStore->newRevisionFromRow( $row, 0, $title ); - } else { - return null; - } - } - - /** - * Generates each row in the contributions list. - * - * Contributions which are marked "top" are currently on top of the history. - * For these contributions, a [rollback] link is shown for users with roll- - * back privileges. The rollback link restores the most recent version that - * was not written by the target user. - * - * @todo This would probably look a lot nicer in a table. - * @param stdClass|mixed $row - * @return string - */ - public function formatRow( $row ) { - $ret = ''; - $classes = []; - $attribs = []; - - $linkRenderer = $this->getLinkRenderer(); - - $page = null; - // Create a title for the revision if possible - // Rows from the hook may not include title information - if ( isset( $row->page_namespace ) && isset( $row->page_title ) ) { - $page = Title::newFromRow( $row ); - } - // Flow overrides the ContribsPager::reallyDoQuery hook, causing this - // function to be called with a special object for $row. It expects us - // skip formatting so that the row can be formatted by the - // ContributionsLineEnding hook below. - // FIXME: have some better way for extensions to provide formatted rows. - $revRecord = $this->tryCreatingRevisionRecord( $row, $page ); - if ( $revRecord && $page ) { - $revRecord = $this->revisionStore->newRevisionFromRow( $row, 0, $page ); - $attribs['data-mw-revid'] = $revRecord->getId(); - - $link = $linkRenderer->makeLink( - $page, - $page->getPrefixedText(), - [ 'class' => 'mw-contributions-title' ], - $page->isRedirect() ? [ 'redirect' => 'no' ] : [] - ); - # Mark current revisions - $topmarktext = ''; - - $pagerTools = new PagerTools( - $revRecord, - null, - $row->rev_id === $row->page_latest && !$row->page_is_new, - $this->hookRunner, - $page, - $this->getContext(), - $this->getLinkRenderer() - ); - if ( $row->rev_id === $row->page_latest ) { - $topmarktext .= '<span class="mw-uctop">' . $this->messages['uctop'] . '</span>'; - $classes[] = 'mw-contributions-current'; - } - if ( $pagerTools->shouldPreventClickjacking() ) { - $this->setPreventClickjacking( true ); - } - $topmarktext .= $pagerTools->toHTML(); - # Is there a visible previous revision? - if ( $revRecord->getParentId() !== 0 && - $revRecord->userCan( RevisionRecord::DELETED_TEXT, $this->getAuthority() ) - ) { - $difftext = $linkRenderer->makeKnownLink( - $page, - new HtmlArmor( $this->messages['diff'] ), - [ 'class' => 'mw-changeslist-diff' ], - [ - 'diff' => 'prev', - 'oldid' => $row->rev_id - ] - ); - } else { - $difftext = $this->messages['diff']; - } - $histlink = $linkRenderer->makeKnownLink( - $page, - new HtmlArmor( $this->messages['hist'] ), - [ 'class' => 'mw-changeslist-history' ], - [ 'action' => 'history' ] - ); - - if ( $row->rev_parent_id === null ) { - // For some reason rev_parent_id isn't populated for this row. - // Its rumoured this is true on wikipedia for some revisions (T36922). - // Next best thing is to have the total number of bytes. - $chardiff = ' <span class="mw-changeslist-separator"></span> '; - $chardiff .= Linker::formatRevisionSize( $row->rev_len ); - $chardiff .= ' <span class="mw-changeslist-separator"></span> '; - } else { - $parentLen = 0; - if ( isset( $this->mParentLens[$row->rev_parent_id] ) ) { - $parentLen = $this->mParentLens[$row->rev_parent_id]; - } - - $chardiff = ' <span class="mw-changeslist-separator"></span> '; - $chardiff .= ChangesList::showCharacterDifference( - $parentLen, - $row->rev_len, - $this->getContext() - ); - $chardiff .= ' <span class="mw-changeslist-separator"></span> '; - } - - $lang = $this->getLanguage(); - - $comment = $this->formattedComments[$row->rev_id]; - - if ( $comment === '' ) { - $defaultComment = $this->messages['changeslist-nocomment']; - $comment = "<span class=\"comment mw-comment-none\">$defaultComment</span>"; - } - - $comment = $lang->getDirMark() . $comment; - - $authority = $this->getAuthority(); - $d = ChangesList::revDateLink( $revRecord, $authority, $lang, $page ); - - // When the author is different from the target, always show user and user talk links - $userlink = ''; - $revUser = $revRecord->getUser(); - $revUserId = $revUser ? $revUser->getId() : 0; - $revUserText = $revUser ? $revUser->getName() : ''; - if ( $this->target !== $revUserText ) { - $userlink = ' <span class="mw-changeslist-separator"></span> ' - . $lang->getDirMark() - . Linker::userLink( $revUserId, $revUserText ); - $userlink .= ' ' . $this->msg( 'parentheses' )->rawParams( - Linker::userTalkLink( $revUserId, $revUserText ) )->escaped() . ' '; - } - - $flags = []; - if ( $revRecord->getParentId() === 0 ) { - $flags[] = ChangesList::flag( 'newpage' ); - } - - if ( $revRecord->isMinor() ) { - $flags[] = ChangesList::flag( 'minor' ); - } - - $del = Linker::getRevDeleteLink( $authority, $revRecord, $page ); - if ( $del !== '' ) { - $del .= ' '; - } - - // While it might be tempting to use a list here - // this would result in clutter and slows down navigating the content - // in assistive technology. - // See https://phabricator.wikimedia.org/T205581#4734812 - $diffHistLinks = Html::rawElement( 'span', - [ 'class' => 'mw-changeslist-links' ], - // The spans are needed to ensure the dividing '|' elements are not - // themselves styled as links. - Html::rawElement( 'span', [], $difftext ) . - ' ' . // Space needed for separating two words. - Html::rawElement( 'span', [], $histlink ) - ); - - # Tags, if any. Save some time using a cache. - [ $tagSummary, $newClasses ] = $this->tagsCache->getWithSetCallback( - $this->tagsCache->makeKey( - $row->ts_tags ?? '', - $this->getUser()->getName(), - $lang->getCode() - ), - fn () => ChangeTags::formatSummaryRow( - $row->ts_tags, - null, - $this->getContext() - ) - ); - $classes = array_merge( $classes, $newClasses ); - - $this->hookRunner->onSpecialContributions__formatRow__flags( - $this->getContext(), $row, $flags ); - - $templateParams = [ - 'del' => $del, - 'timestamp' => $d, - 'diffHistLinks' => $diffHistLinks, - 'charDifference' => $chardiff, - 'flags' => $flags, - 'articleLink' => $link, - 'userlink' => $userlink, - 'logText' => $comment, - 'topmarktext' => $topmarktext, - 'tagSummary' => $tagSummary, - ]; - - # Denote if username is redacted for this edit - if ( $revRecord->isDeleted( RevisionRecord::DELETED_USER ) ) { - $templateParams['rev-deleted-user-contribs'] = - $this->msg( 'rev-deleted-user-contribs' )->escaped(); - } - - $ret = $this->templateParser->processTemplate( - 'SpecialContributionsLine', - $templateParams - ); - } - - // Let extensions add data - $this->hookRunner->onContributionsLineEnding( $this, $ret, $row, $classes, $attribs ); - $attribs = array_filter( $attribs, - [ Sanitizer::class, 'isReservedDataAttribute' ], - ARRAY_FILTER_USE_KEY - ); - - // TODO: Handle exceptions in the catch block above. Do any extensions rely on - // receiving empty rows? - - if ( $classes === [] && $attribs === [] && $ret === '' ) { - wfDebug( "Dropping Special:Contribution row that could not be formatted" ); - return "<!-- Could not format Special:Contribution row. -->\n"; - } - $attribs['class'] = $classes; - - // FIXME: The signature of the ContributionsLineEnding hook makes it - // very awkward to move this LI wrapper into the template. - return Html::rawElement( 'li', $attribs, $ret ) . "\n"; - } - - /** - * Overwrite Pager function and return a helpful comment - * @return string - */ - protected function getSqlComment() { - if ( $this->namespace || $this->deletedOnly ) { - // potentially slow, see CR r58153 - return 'contributions page filtered for namespace or RevisionDeleted edits'; - } else { - return 'contributions page unfiltered'; - } - } - - /** - * @deprecated since 1.38, use ::setPreventClickjacking() instead - */ - protected function preventClickjacking() { - $this->setPreventClickjacking( true ); - } - - /** - * @param bool $enable - * @since 1.38 - */ - protected function setPreventClickjacking( bool $enable ) { - $this->preventClickjacking = $enable; - } - - /** - * @return bool - */ - public function getPreventClickjacking() { - return $this->preventClickjacking; - } - -} |