59 private $linkBatchFactory;
62 private $commentStore;
65 private $contentHandlerFactory;
68 private $groupPermissionsLookup;
71 private $loadBalancer;
74 private $revisionLookup;
77 private $namespaceInfo;
80 private $userOptionsLookup;
83 private $commentFormatter;
107 parent::__construct(
'Newpages' );
108 $this->linkBatchFactory = $linkBatchFactory;
109 $this->commentStore = $commentStore;
110 $this->contentHandlerFactory = $contentHandlerFactory;
111 $this->groupPermissionsLookup = $groupPermissionsLookup;
112 $this->loadBalancer = $loadBalancer;
113 $this->revisionLookup = $revisionLookup;
114 $this->namespaceInfo = $namespaceInfo;
115 $this->userOptionsLookup = $userOptionsLookup;
116 $this->commentFormatter = $commentFormatter;
128 $this->userOptionsLookup->getBoolOption( $this->getUser(),
'newpageshidepatrolled' )
134 $this->userOptionsLookup->getIntOption( $this->getUser(),
'rclimit' )
146 $this->customFilters = [];
147 $this->
getHookRunner()->onSpecialNewPagesFilters( $this, $this->customFilters );
149 foreach ( $this->customFilters as $key => $params ) {
150 $opts->
add( $key, $params[
'default'] );
165 $bits = preg_split(
'/\s*,\s*/', trim( $par ) );
166 foreach ( $bits as $bit ) {
167 if ( $bit ===
'shownav' ) {
168 $this->showNavigation =
true;
170 if ( $bit ===
'hideliu' ) {
171 $this->opts->setValue(
'hideliu',
true );
173 if ( $bit ===
'hidepatrolled' ) {
174 $this->opts->setValue(
'hidepatrolled',
true );
176 if ( $bit ===
'hidebots' ) {
177 $this->opts->setValue(
'hidebots',
true );
179 if ( $bit ===
'showredirs' ) {
180 $this->opts->setValue(
'hideredirs',
false );
182 if ( is_numeric( $bit ) ) {
183 $this->opts->setValue(
'limit', intval( $bit ) );
187 if ( preg_match(
'/^limit=(\d+)$/', $bit, $m ) ) {
188 $this->opts->setValue(
'limit', intval( $m[1] ) );
191 if ( preg_match(
'/^offset=([^=]+)$/', $bit, $m ) ) {
192 $this->opts->setValue(
'offset', intval( $m[1] ) );
194 if ( preg_match(
'/^username=(.*)$/', $bit, $m ) ) {
195 $this->opts->setValue(
'username', $m[1] );
197 if ( preg_match(
'/^namespace=(.*)$/', $bit, $m ) ) {
199 if ( $ns !==
false ) {
200 $this->opts->setValue(
'namespace', $ns );
217 $this->showNavigation = !$this->
including();
218 $this->
setup( $par );
226 $feedType = $this->opts->getValue(
'feed' );
228 $this->
feed( $feedType );
233 $allValues = $this->opts->getAllValues();
234 unset( $allValues[
'feed'] );
238 $pager = $this->getNewPagesPager();
239 $pager->mLimit = $this->opts->getValue(
'limit' );
240 $pager->mOffset = $this->opts->getValue(
'offset' );
242 if ( $pager->getNumRows() ) {
244 if ( $this->showNavigation ) {
245 $navigation = $pager->getNavigationBar();
247 $out->addHTML( $navigation . $pager->getBody() . $navigation );
249 $out->addModuleStyles(
'mediawiki.interface.helpers.styles' );
251 $out->addWikiMsg(
'specialpage-empty' );
257 $showhide = [ $this->
msg(
'show' )->escaped(), $this->
msg(
'hide' )->escaped() ];
261 'hideliu' =>
'newpages-showhide-registered',
262 'hidepatrolled' =>
'newpages-showhide-patrolled',
263 'hidebots' =>
'newpages-showhide-bots',
264 'hideredirs' =>
'newpages-showhide-redirect'
266 foreach ( $this->customFilters as $key => $params ) {
267 $filters[$key] = $params[
'msg'];
271 if ( !$this->canAnonymousUsersCreatePages() ) {
272 unset( $filters[
'hideliu'] );
274 if ( !$this->
getUser()->useNPPatrol() ) {
275 unset( $filters[
'hidepatrolled'] );
279 $changed = $this->opts->getChangedValues();
280 unset( $changed[
'offset'] );
286 foreach ( $changed as $key => $value ) {
287 if ( array_key_exists( $key, $filters ) ) {
288 $changed[$key] = $changed[$key] ?
'1' :
'0';
294 foreach ( $filters as $key => $msg ) {
295 $onoff = 1 - $this->opts->getValue( $key );
296 $link = $linkRenderer->makeLink(
300 [ $key => $onoff ] + $changed
302 $links[$key] = $this->
msg( $msg )->rawParams( $link )->escaped();
312 $this->opts->consumeValue(
'offset' );
313 $namespace = $this->opts->consumeValue(
'namespace' );
314 $username = $this->opts->consumeValue(
'username' );
315 $tagFilterVal = $this->opts->consumeValue(
'tagfilter' );
316 $nsinvert = $this->opts->consumeValue(
'invert' );
317 $nsassociated = $this->opts->consumeValue(
'associated' );
319 $size = $this->opts->consumeValue(
'size' );
320 $max = $this->opts->consumeValue(
'size-mode' ) ===
'max';
323 $ut = Title::makeTitleSafe(
NS_USER, $username );
324 $userText = $ut ? $ut->getText() :
'';
328 'type' =>
'namespaceselect',
329 'name' =>
'namespace',
330 'label-message' =>
'namespace',
331 'default' => $namespace,
336 'label-message' =>
'invert',
337 'default' => $nsinvert,
338 'tooltip' =>
'invert',
342 'name' =>
'associated',
343 'label-message' =>
'namespace_association',
344 'default' => $nsassociated,
345 'tooltip' =>
'namespace_association',
348 'type' =>
'tagfilter',
349 'name' =>
'tagfilter',
350 'label-message' =>
'tag-filter',
351 'default' => $tagFilterVal,
355 'name' =>
'username',
356 'label-message' =>
'newpages-username',
357 'default' => $userText,
358 'id' =>
'mw-np-username',
362 'type' =>
'sizefilter',
364 'default' => ( $max ? -1 : 1 ) * $size,
371 foreach ( $this->opts->getUnconsumedValues() as $key => $value ) {
372 $htmlForm->addHiddenField( $key, $value );
377 ->setFormIdentifier(
'newpagesform' )
385 ->setSubmitTextMsg(
'newpages-submit' )
386 ->setWrapperLegendMsg(
'newpages' )
387 ->addFooterHtml( Html::rawElement(
393 $out->addModuleStyles(
'mediawiki.special' );
404 $this->commentStore->getComment(
'rc_comment', $result )
406 $revRecord->setVisibility( (
int)$result->rc_deleted );
409 (
int)$result->rc_user,
410 $result->rc_user_text
412 $revRecord->setUser( $user );
425 $title = Title::newFromRow( $result );
429 $revRecord = $this->revisionFromRcResult( $result,
$title );
432 $attribs = [
'data-mw-revid' => $result->rev_id ];
434 $lang = $this->getLanguage();
435 $dm =
$lang->getDirMark();
437 $spanTime = Html::element(
'span', [
'class' =>
'mw-newpages-time' ],
438 $lang->userTimeAndDate( $result->rc_timestamp, $this->getUser() )
440 $linkRenderer = $this->getLinkRenderer();
441 $time = $linkRenderer->makeKnownLink(
445 [
'oldid' => $result->rc_this_oldid ]
448 $query =
$title->isRedirect() ? [
'redirect' =>
'no' ] : [];
450 $plink = $linkRenderer->makeKnownLink(
453 [
'class' =>
'mw-newpages-pagename' ],
457 $linkArr[] = $linkRenderer->makeKnownLink(
459 $this->msg(
'hist' )->text(),
460 [
'class' =>
'mw-newpages-history' ],
461 [
'action' =>
'history' ]
463 if ( $this->contentHandlerFactory->getContentHandler(
$title->getContentModel() )
464 ->supportsDirectEditing()
466 $linkArr[] = $linkRenderer->makeKnownLink(
468 $this->msg(
'editlink' )->text(),
469 [
'class' =>
'mw-newpages-edit' ],
470 [
'action' =>
'edit' ]
473 $links = $this->msg(
'parentheses' )->rawParams( $this->getLanguage()
474 ->pipeList( $linkArr ) )->escaped();
476 $length = Html::rawElement(
478 [
'class' =>
'mw-newpages-length' ],
479 $this->msg(
'brackets' )->rawParams(
480 $this->msg(
'nbytes' )->numParams( $result->length )->escaped()
484 $ulink = Linker::revUserTools( $revRecord );
485 $comment = $this->commentFormatter->formatRevision( $revRecord, $this->
getAuthority() );
487 if ( $this->patrollable( $result ) ) {
488 $classes[] =
'not-patrolled';
491 # Add a class for zero byte pages
492 if ( $result->length == 0 ) {
493 $classes[] =
'mw-newpages-zero-byte-page';
497 if ( isset( $result->ts_tags ) ) {
503 $classes = array_merge( $classes, $newClasses );
508 # Display the old title if the namespace/title has been changed
510 $oldTitle = Title::makeTitle( $result->rc_namespace, $result->rc_title );
512 if ( !
$title->equals( $oldTitle ) ) {
513 $oldTitleText = $oldTitle->getPrefixedText();
514 $oldTitleText = Html::rawElement(
516 [
'class' =>
'mw-newpages-oldtitle' ],
517 $this->msg(
'rc-old-title' )->params( $oldTitleText )->escaped()
521 $ret =
"{$time} {$dm}{$plink} {$links} {$dm}{$length} {$dm}{$ulink} {$comment} "
522 .
"{$tagDisplay} {$oldTitleText}";
525 $this->getHookRunner()->onNewPagesLineEnding(
526 $this, $ret, $result, $classes, $attribs );
527 $attribs = array_filter( $attribs,
528 [ Sanitizer::class,
'isReservedDataAttribute' ],
533 $attribs[
'class'] = $classes;
536 return Html::rawElement(
'li', $attribs, $ret ) .
"\n";
539 private function getNewPagesPager() {
542 $this->groupPermissionsLookup,
543 $this->getHookContainer(),
544 $this->linkBatchFactory,
546 $this->namespaceInfo,
558 return ( $this->
getUser()->useNPPatrol() && !$result->rc_patrolled );
567 if ( !$this->getConfig()->
get( MainConfigNames::Feed ) ) {
568 $this->getOutput()->addWikiMsg(
'feed-unavailable' );
573 $feedClasses = $this->getConfig()->get( MainConfigNames::FeedClasses );
574 if ( !isset( $feedClasses[
$type] ) ) {
575 $this->getOutput()->addWikiMsg(
'feed-invalid' );
580 $feed =
new $feedClasses[
$type](
582 $this->msg(
'tagline' )->text(),
583 $this->getPageTitle()->getFullURL()
586 $pager = $this->getNewPagesPager();
587 $limit = $this->opts->getValue(
'limit' );
588 $pager->mLimit = min( $limit, $this->getConfig()->
get( MainConfigNames::FeedLimit ) );
591 if ( $pager->getNumRows() > 0 ) {
592 foreach ( $pager->mResult as $row ) {
593 $feed->outItem( $this->feedItem( $row ) );
600 $desc = $this->getDescription();
601 $code = $this->getConfig()->get( MainConfigNames::LanguageCode );
602 $sitename = $this->getConfig()->get( MainConfigNames::Sitename );
604 return "$sitename - $desc [$code]";
608 $title = Title::makeTitle( intval( $row->rc_namespace ), $row->rc_title );
610 $date = $row->rc_timestamp;
611 $comments =
$title->getTalkPage()->getFullURL();
614 $title->getPrefixedText(),
615 $this->feedItemDesc( $row ),
618 $this->feedItemAuthor( $row ),
627 return $row->rc_user_text ??
'';
631 $revisionRecord = $this->revisionLookup->getRevisionById( $row->rev_id );
632 if ( !$revisionRecord ) {
636 $content = $revisionRecord->getContent( SlotRecord::MAIN );
642 $revUser = $revisionRecord->getUser();
643 $revUserText = $revUser ? $revUser->getName() :
'';
644 $revComment = $revisionRecord->getComment();
645 $revCommentText = $revComment ? $revComment->text :
'';
646 return '<p>' . htmlspecialchars( $revUserText ) .
647 $this->msg(
'colon-separator' )->inContentLanguage()->escaped() .
648 htmlspecialchars( FeedItem::stripComment( $revCommentText ) ) .
649 "</p>\n<hr />\n<div>" .
650 nl2br( htmlspecialchars(
$content->serialize() ) ) .
"</div>";
653 private function canAnonymousUsersCreatePages() {
654 return $this->groupPermissionsLookup->groupHasPermission(
'*',
'createpage' ) ||
655 $this->groupPermissionsLookup->groupHasPermission(
'*',
'createtalk' );
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
Marks HTML that shouldn't be escaped.
Shortcut to construct an includable special page.
A class containing constants representing the names of configuration variables.
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
A special page that list newly created pages.
__construct(LinkBatchFactory $linkBatchFactory, CommentStore $commentStore, IContentHandlerFactory $contentHandlerFactory, GroupPermissionsLookup $groupPermissionsLookup, ILoadBalancer $loadBalancer, RevisionLookup $revisionLookup, NamespaceInfo $namespaceInfo, UserOptionsLookup $userOptionsLookup, CommentFormatter $commentFormatter)
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
patrollable( $result)
Should a specific result row provide "patrollable" links?
feed( $type)
Output a subscription feed listing recent edits to this page.
execute( $par)
Show a form for filtering namespace and username.
formatRow( $result)
Format a row, providing the timestamp, links to the page/history, size, user links,...
revisionFromRcResult(stdClass $result, Title $title)
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getOutput()
Get the OutputPage being used for this instance.
getUser()
Shortcut to get the User executing this instance.
getContext()
Gets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getRequest()
Get the WebRequest being used for this instance.
getPageTitle( $subpage=false)
Get a self-referential title object.
getLanguage()
Shortcut to get user's language.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
including( $x=null)
Whether the special page is being evaluated via transclusion.
if(!isset( $args[0])) $lang