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;
125 $opts->
add(
'hideliu',
false );
128 $this->userOptionsLookup->getBoolOption( $this->getUser(),
'newpageshidepatrolled' )
130 $opts->
add(
'hidebots',
false );
131 $opts->
add(
'hideredirs',
true );
134 $this->userOptionsLookup->getIntOption( $this->getUser(),
'rclimit' )
136 $opts->
add(
'offset',
'' );
137 $opts->
add(
'namespace',
'0' );
138 $opts->
add(
'username',
'' );
139 $opts->
add(
'feed',
'' );
140 $opts->
add(
'tagfilter',
'' );
141 $opts->
add(
'invert',
false );
142 $opts->
add(
'associated',
false );
143 $opts->
add(
'size-mode',
'max' );
144 $opts->
add(
'size', 0 );
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,
368 $htmlForm = HTMLForm::factory(
'ooui', $formDescriptor, $this->
getContext() );
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.
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