46 parent::__construct(
'Newpages' );
52 protected function setup( $par ) {
55 $opts->
add(
'hideliu',
false );
56 $opts->
add(
'hidepatrolled', $this->
getUser()->getBoolOption(
'newpageshidepatrolled' ) );
57 $opts->
add(
'hidebots',
false );
58 $opts->
add(
'hideredirs',
true );
59 $opts->
add(
'limit', $this->
getUser()->getIntOption(
'rclimit' ) );
60 $opts->
add(
'offset',
'' );
61 $opts->
add(
'namespace',
'0' );
62 $opts->
add(
'username',
'' );
63 $opts->
add(
'feed',
'' );
64 $opts->
add(
'tagfilter',
'' );
65 $opts->
add(
'invert',
false );
66 $opts->
add(
'associated',
false );
67 $opts->
add(
'size-mode',
'max' );
68 $opts->
add(
'size', 0 );
70 $this->customFilters = [];
71 $this->
getHookRunner()->onSpecialNewPagesFilters( $this, $this->customFilters );
73 foreach ( $this->customFilters as $key => $params ) {
74 $opts->
add( $key, $params[
'default'] );
89 $bits = preg_split(
'/\s*,\s*/', trim( $par ) );
90 foreach ( $bits as $bit ) {
91 if ( $bit ===
'shownav' ) {
92 $this->showNavigation =
true;
94 if ( $bit ===
'hideliu' ) {
95 $this->opts->setValue(
'hideliu',
true );
97 if ( $bit ===
'hidepatrolled' ) {
98 $this->opts->setValue(
'hidepatrolled',
true );
100 if ( $bit ===
'hidebots' ) {
101 $this->opts->setValue(
'hidebots',
true );
103 if ( $bit ===
'showredirs' ) {
104 $this->opts->setValue(
'hideredirs',
false );
106 if ( is_numeric( $bit ) ) {
107 $this->opts->setValue(
'limit', intval( $bit ) );
111 if ( preg_match(
'/^limit=(\d+)$/', $bit, $m ) ) {
112 $this->opts->setValue(
'limit', intval( $m[1] ) );
115 if ( preg_match(
'/^offset=([^=]+)$/', $bit, $m ) ) {
116 $this->opts->setValue(
'offset', intval( $m[1] ) );
118 if ( preg_match(
'/^username=(.*)$/', $bit, $m ) ) {
119 $this->opts->setValue(
'username', $m[1] );
121 if ( preg_match(
'/^namespace=(.*)$/', $bit, $m ) ) {
123 if ( $ns !==
false ) {
124 $this->opts->setValue(
'namespace', $ns );
141 $this->showNavigation = !$this->
including();
142 $this->
setup( $par );
150 $feedType = $this->opts->getValue(
'feed' );
152 $this->
feed( $feedType );
157 $allValues = $this->opts->getAllValues();
158 unset( $allValues[
'feed'] );
163 $pager->mLimit = $this->opts->getValue(
'limit' );
164 $pager->mOffset = $this->opts->getValue(
'offset' );
166 if ( $pager->getNumRows() ) {
168 if ( $this->showNavigation ) {
169 $navigation = $pager->getNavigationBar();
171 $out->addHTML( $navigation . $pager->getBody() . $navigation );
173 $out->addModuleStyles(
'mediawiki.interface.helpers.styles' );
175 $out->addWikiMsg(
'specialpage-empty' );
181 $showhide = [ $this->
msg(
'show' )->escaped(), $this->
msg(
'hide' )->escaped() ];
185 'hideliu' =>
'rcshowhideliu',
186 'hidepatrolled' =>
'rcshowhidepatr',
187 'hidebots' =>
'rcshowhidebots',
188 'hideredirs' =>
'whatlinkshere-hideredirs'
190 foreach ( $this->customFilters as $key => $params ) {
191 $filters[$key] = $params[
'msg'];
196 unset( $filters[
'hideliu'] );
198 if ( !$this->
getUser()->useNPPatrol() ) {
199 unset( $filters[
'hidepatrolled'] );
203 $changed = $this->opts->getChangedValues();
204 unset( $changed[
'offset'] );
210 foreach ( $changed as $key => $value ) {
211 if ( array_key_exists( $key, $filters ) ) {
212 $changed[$key] = $changed[$key] ?
'1' :
'0';
218 foreach ( $filters as $key => $msg ) {
219 $onoff = 1 - $this->opts->getValue( $key );
224 [ $key => $onoff ] + $changed
226 $links[$key] = $this->
msg( $msg )->rawParams( $link )->escaped();
236 $this->opts->consumeValue(
'offset' );
237 $namespace = $this->opts->consumeValue(
'namespace' );
238 $username = $this->opts->consumeValue(
'username' );
239 $tagFilterVal = $this->opts->consumeValue(
'tagfilter' );
240 $nsinvert = $this->opts->consumeValue(
'invert' );
241 $nsassociated = $this->opts->consumeValue(
'associated' );
243 $size = $this->opts->consumeValue(
'size' );
244 $max = $this->opts->consumeValue(
'size-mode' ) ===
'max';
247 $ut = Title::makeTitleSafe(
NS_USER, $username );
248 $userText = $ut ? $ut->getText() :
'';
252 'type' =>
'namespaceselect',
253 'name' =>
'namespace',
254 'label-message' =>
'namespace',
255 'default' => $namespace,
260 'label-message' =>
'invert',
261 'default' => $nsinvert,
262 'tooltip' =>
'invert',
266 'name' =>
'associated',
267 'label-message' =>
'namespace_association',
268 'default' => $nsassociated,
269 'tooltip' =>
'namespace_association',
272 'type' =>
'tagfilter',
273 'name' =>
'tagfilter',
274 'label-raw' => $this->
msg(
'tag-filter' )->parse(),
275 'default' => $tagFilterVal,
279 'name' =>
'username',
280 'label-message' =>
'newpages-username',
281 'default' => $userText,
282 'id' =>
'mw-np-username',
286 'type' =>
'sizefilter',
288 'default' => -$max * $size,
292 $htmlForm = HTMLForm::factory(
'ooui', $formDescriptor, $this->
getContext() );
295 foreach ( $this->opts->getUnconsumedValues() as $key => $value ) {
296 $htmlForm->addHiddenField( $key, $value );
301 ->setFormIdentifier(
'newpagesform' )
309 ->setSubmitText( $this->
msg(
'newpages-submit' )->text() )
310 ->setWrapperLegend( $this->
msg(
'newpages' )->text() )
311 ->addFooterText( Html::rawElement(
317 $out->addModuleStyles(
'mediawiki.special' );
328 CommentStore::getStore()->getComment(
'rc_comment', $result )
330 $revRecord->setVisibility( (
int)$result->rc_deleted );
333 (
int)$result->rc_user,
334 $result->rc_user_text,
335 (
int)$result->rc_actor
337 $revRecord->setUser( $user );
350 $title = Title::newFromRow( $result );
354 $revRecord = $this->revisionFromRcResult( $result,
$title );
357 $attribs = [
'data-mw-revid' => $result->rev_id ];
359 $lang = $this->getLanguage();
360 $dm =
$lang->getDirMark();
362 $spanTime = Html::element(
'span', [
'class' =>
'mw-newpages-time' ],
363 $lang->userTimeAndDate( $result->rc_timestamp, $this->getUser() )
365 $linkRenderer = $this->getLinkRenderer();
366 $time = $linkRenderer->makeKnownLink(
370 [
'oldid' => $result->rc_this_oldid ]
373 $query =
$title->isRedirect() ? [
'redirect' =>
'no' ] : [];
375 $plink = $linkRenderer->makeKnownLink(
378 [
'class' =>
'mw-newpages-pagename' ],
382 $linkArr[] = $linkRenderer->makeKnownLink(
384 $this->msg(
'hist' )->text(),
385 [
'class' =>
'mw-newpages-history' ],
386 [
'action' =>
'history' ]
388 if ( MediaWikiServices::getInstance()
389 ->getContentHandlerFactory()
390 ->getContentHandler(
$title->getContentModel() )
391 ->supportsDirectEditing()
393 $linkArr[] = $linkRenderer->makeKnownLink(
395 $this->msg(
'editlink' )->text(),
396 [
'class' =>
'mw-newpages-edit' ],
397 [
'action' =>
'edit' ]
400 $links = $this->msg(
'parentheses' )->rawParams( $this->getLanguage()
401 ->pipeList( $linkArr ) )->escaped();
403 $length = Html::rawElement(
405 [
'class' =>
'mw-newpages-length' ],
406 $this->msg(
'brackets' )->rawParams(
407 $this->msg(
'nbytes' )->numParams( $result->length )->escaped()
414 if ( $this->patrollable( $result ) ) {
415 $classes[] =
'not-patrolled';
418 # Add a class for zero byte pages
419 if ( $result->length == 0 ) {
420 $classes[] =
'mw-newpages-zero-byte-page';
424 if ( isset( $result->ts_tags ) ) {
430 $classes = array_merge( $classes, $newClasses );
435 # Display the old title if the namespace/title has been changed
437 $oldTitle = Title::makeTitle( $result->rc_namespace, $result->rc_title );
439 if ( !
$title->equals( $oldTitle ) ) {
440 $oldTitleText = $oldTitle->getPrefixedText();
441 $oldTitleText = Html::rawElement(
443 [
'class' =>
'mw-newpages-oldtitle' ],
444 $this->msg(
'rc-old-title' )->params( $oldTitleText )->escaped()
448 $ret =
"{$time} {$dm}{$plink} {$links} {$dm}{$length} {$dm}{$ulink} {$comment} "
449 .
"{$tagDisplay} {$oldTitleText}";
452 $this->getHookRunner()->onNewPagesLineEnding(
453 $this, $ret, $result, $classes, $attribs );
454 $attribs = array_filter( $attribs,
455 [ Sanitizer::class,
'isReservedDataAttribute' ],
459 if ( count( $classes ) ) {
460 $attribs[
'class'] = implode(
' ', $classes );
463 return Html::rawElement(
'li', $attribs, $ret ) .
"\n";
473 return ( $this->
getUser()->useNPPatrol() && !$result->rc_patrolled );
482 if ( !$this->getConfig()->
get(
'Feed' ) ) {
483 $this->getOutput()->addWikiMsg(
'feed-unavailable' );
488 $feedClasses = $this->getConfig()->get(
'FeedClasses' );
489 if ( !isset( $feedClasses[
$type] ) ) {
490 $this->getOutput()->addWikiMsg(
'feed-invalid' );
495 $feed =
new $feedClasses[
$type](
497 $this->msg(
'tagline' )->text(),
498 $this->getPageTitle()->getFullURL()
502 $limit = $this->opts->getValue(
'limit' );
503 $pager->mLimit = min( $limit, $this->getConfig()->
get(
'FeedLimit' ) );
506 if ( $pager->getNumRows() > 0 ) {
507 foreach ( $pager->mResult as $row ) {
508 $feed->outItem( $this->feedItem( $row ) );
515 $desc = $this->getDescription();
516 $code = $this->getConfig()->get(
'LanguageCode' );
517 $sitename = $this->getConfig()->get(
'Sitename' );
519 return "$sitename - $desc [$code]";
523 $title = Title::makeTitle( intval( $row->rc_namespace ), $row->rc_title );
525 $date = $row->rc_timestamp;
526 $comments =
$title->getTalkPage()->getFullURL();
529 $title->getPrefixedText(),
530 $this->feedItemDesc( $row ),
533 $this->feedItemAuthor( $row ),
542 return $row->rc_user_text ??
'';
546 $revisionRecord = MediaWikiServices::getInstance()
547 ->getRevisionLookup()
548 ->getRevisionById( $row->rev_id );
549 if ( !$revisionRecord ) {
553 $content = $revisionRecord->getContent( SlotRecord::MAIN );
559 $revUser = $revisionRecord->getUser();
560 $revUserText = $revUser ? $revUser->getName() :
'';
561 $revComment = $revisionRecord->getComment();
562 $revCommentText = $revComment ? $revComment->text :
'';
563 return '<p>' . htmlspecialchars( $revUserText ) .
564 $this->msg(
'colon-separator' )->inContentLanguage()->escaped() .
565 htmlspecialchars( FeedItem::stripComment( $revCommentText ) ) .
566 "</p>\n<hr />\n<div>" .
567 nl2br( htmlspecialchars(
$content->serialize() ) ) .
"</div>";
571 $pm = MediaWikiServices::getInstance()->getPermissionManager();
572 return ( $pm->groupHasPermission(
'*',
'createpage' ) ||
573 $pm->groupHasPermission(
'*',
'createtalk' )
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
A base class for outputting syndication feeds (e.g.
Marks HTML that shouldn't be escaped.
Shortcut to construct an includable special page.
static revComment( $rev, $local=false, $isPublic=false, $useParentheses=true)
Wrap and format the given revision's comment block, if the current user is allowed to view it.
static revUserTools( $rev, $isPublic=false, $useParentheses=true)
Generate a user tool link cluster if the current user is allowed to view it.
A special page that list newly created pages.
canAnonymousUsersCreatePages()
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?
getCacheTTL()
Stable to override.
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.
MediaWiki Linker LinkRenderer null $linkRenderer
Represents a title within MediaWiki.
if(!isset( $args[0])) $lang