45 private const DIR_PREV = 0;
46 private const DIR_NEXT = 1;
64 return $this->
msg(
'history-title', $this->
getTitle()->getPrefixedText() )->text();
69 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
70 $subtitle = $linkRenderer->makeKnownLink(
72 $this->
msg(
'viewpagelogs' )->text(),
74 [
'page' => $this->
getTitle()->getPrefixedText() ]
82 . $this->
msg(
'word-separator' )->escaped()
83 . $this->
msg(
'parentheses' )
84 ->rawParams( $this->
getLanguage()->pipeList( $links ) )
87 return Html::rawElement(
'div', [
'class' =>
'mw-history-subtitle' ], $subtitle );
94 private function preCacheMessages() {
96 if ( !isset( $this->message ) ) {
98 $msgs = [
'cur',
'tooltip-cur',
'last',
'tooltip-last',
'pipe-separator' ];
99 foreach ( $msgs as $msg ) {
100 $this->message[$msg] = $this->
msg( $msg )->escaped();
109 private function getTimestampFromRequest(
WebRequest $request ) {
111 $year = $request->
getInt(
'year' );
112 $month = $request->
getInt(
'month' );
114 if ( $year !== 0 || $month !== 0 ) {
118 if ( $month < 1 || $month > 12 ) {
123 $day = cal_days_in_month( CAL_GREGORIAN, $month, $year );
126 $month = str_pad( (
string)$month, 2,
"0", STR_PAD_LEFT );
127 $day = str_pad( (
string)$day, 2,
"0", STR_PAD_LEFT );
130 $before = $request->
getVal(
'date-range-to' );
132 $parts = explode(
'-', $before );
135 if ( count( $parts ) === 3 ) {
140 return $year && $month && $day ? $year .
'-' . $month .
'-' . $day :
'';
150 $config = $this->context->getConfig();
151 $services = MediaWikiServices::getInstance();
160 $watchlistManager = $services->getWatchlistManager();
161 $hasUnseenRevisionMarkers = $config->get( MainConfigNames::ShowUpdatedMarker ) &&
162 $watchlistManager->getTitleNotificationTimestamp(
167 !$hasUnseenRevisionMarkers &&
168 $out->checkLastModified( $this->getWikiPage()->getTouched() )
173 $this->preCacheMessages();
175 # Fill in the file cache if not set already
178 if ( !$cache->isCacheGood( ) ) {
179 ob_start( [ &$cache,
'saveToFileCache' ] );
184 $out->setFeedAppendQuery(
'action=history' );
185 $out->addModules(
'mediawiki.action.history' );
186 $out->addModuleStyles( [
187 'mediawiki.interface.helpers.styles',
188 'mediawiki.action.history.styles',
189 'mediawiki.special.changeslist',
193 $feedType = $request->
getRawVal(
'feed' );
194 if ( $feedType !==
null ) {
195 $this->feed( $feedType );
200 'https://meta.wikimedia.org/wiki/Special:MyLanguage/Help:Page_history',
206 $send404Code = $config->get( MainConfigNames::Send404Code );
207 if ( $send404Code ) {
208 $out->setStatusCode( 404 );
210 $out->addWikiMsg(
'nohistory' );
214 # show deletion/move log if there is an entry
217 [
'delete',
'move',
'protect' ],
221 'conds' => [
'log_action != ' .
$dbr->addQuotes(
'revision' ) ],
222 'showIfEmpty' =>
false,
223 'msgKey' => [
'moveddeleted-notice' ]
230 $ts = $this->getTimestampFromRequest( $request );
231 $tagFilter = $request->
getVal(
'tagfilter' );
236 if ( $request->
getBool(
'deleted' ) ) {
237 $conds = [
'rev_deleted != 0' ];
247 'default' =>
'history',
252 'label' => $this->
msg(
'date-range-to' )->text(),
253 'name' =>
'date-range-to',
256 'label-message' =>
'tag-filter',
257 'type' =>
'tagfilter',
259 'name' =>
'tagfilter',
260 'value' => $tagFilter,
263 if ( $this->
getAuthority()->isAllowed(
'deletedhistory' ) ) {
266 'label' => $this->
msg(
'history-show-deleted' )->text(),
267 'default' => $request->
getBool(
'deleted' ),
277 ->setCollapsibleOptions(
true )
278 ->setId(
'mw-history-searchform' )
279 ->setSubmitTextMsg(
'historyaction-submit' )
280 ->setWrapperAttributes( [
'id' =>
'mw-history-search' ] )
281 ->setWrapperLegendMsg(
'history-fieldset-title' )
284 $out->addHTML( $htmlForm->getHTML(
false ) );
292 $dateComponents = explode(
'-', $ts );
293 if ( count( $dateComponents ) > 1 ) {
294 $y = (int)$dateComponents[0];
295 $m = (int)$dateComponents[1];
296 $d = (int)$dateComponents[2];
309 $services->getLinkBatchFactory(),
311 $services->getCommentFormatter(),
312 $services->getHookContainer()
315 $pager->getNavigationBar() .
317 $pager->getNavigationBar()
319 $out->setPreventClickjacking( $pager->getPreventClickjacking() );
334 private function fetchRevisions( $limit, $offset, $direction ) {
342 if ( $direction === self::DIR_PREV ) {
343 [ $dirs, $oper ] = [
"ASC",
">=" ];
345 [ $dirs, $oper ] = [
"DESC",
"<=" ];
349 $offsets = [
"rev_timestamp $oper " .
$dbr->addQuotes(
$dbr->timestamp( $offset ) ) ];
356 $revQuery = MediaWikiServices::getInstance()->getRevisionStore()->getQueryInfo();
358 $res =
$dbr->newSelectQueryBuilder()
360 ->where( [
'rev_page' => $page_id ] )
361 ->andWhere( $offsets )
362 ->useIndex( [
'revision' =>
'rev_page_timestamp' ] )
363 ->orderBy( [
'rev_timestamp' ], $dirs )
365 ->caller( __METHOD__ )
376 private function feed(
$type ) {
382 $feedClasses = $this->context->getConfig()->get( MainConfigNames::FeedClasses );
384 $feed =
new $feedClasses[
$type](
385 $this->
getTitle()->getPrefixedText() .
' - ' .
386 $this->
msg(
'history-feed-title' )->inContentLanguage()->text(),
387 $this->
msg(
'history-feed-description' )->inContentLanguage()->text(),
388 $this->
getTitle()->getFullURL(
'action=history' )
393 $limit = $request->
getInt(
'limit', 10 );
396 $this->context->getConfig()->get( MainConfigNames::FeedLimit )
399 $items = $this->fetchRevisions( $limit, 0, self::DIR_NEXT );
402 $formattedComments = MediaWikiServices::getInstance()->getRowCommentFormatter()
403 ->formatRows( $items,
'rev_comment' );
407 if ( $items->numRows() ) {
408 foreach ( $items as $i => $row ) {
409 $feed->outItem( $this->feedItem( $row, $formattedComments[$i] ) );
412 $feed->outItem( $this->feedEmpty() );
417 private function feedEmpty() {
419 $this->
msg(
'nohistory' )->inContentLanguage()->text(),
420 $this->
msg(
'history-feed-empty' )->inContentLanguage()->parseAsBlock(),
424 $this->
getTitle()->getTalkPage()->getFullURL()
437 private function feedItem( $row, $formattedComment ) {
438 $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
439 $rev = $revisionStore->newRevisionFromRow( $row, 0, $this->
getTitle() );
440 $prevRev = $revisionStore->getPreviousRevision( $rev );
441 $revComment = $rev->getComment() ===
null ? null : $rev->getComment()->text;
442 $text = FeedUtils::formatDiffRow2(
444 $prevRev ? $prevRev->getId() :
false,
446 $rev->getTimestamp(),
449 $revUserText = $rev->getUser() ? $rev->getUser()->getName() :
'';
450 if ( $revComment ==
'' ) {
451 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
452 $title = $this->
msg(
'history-feed-item-nocomment',
454 $contLang->timeanddate( $rev->getTimestamp() ),
455 $contLang->date( $rev->getTimestamp() ),
456 $contLang->time( $rev->getTimestamp() )
457 )->inContentLanguage()->text();
460 $this->
msg(
'colon-separator' )->inContentLanguage()->text() .
461 FeedItem::stripComment( $revComment );
467 $this->
getTitle()->getFullURL(
'diff=' . $rev->getId() .
'&oldid=prev' ),
468 $rev->getTimestamp(),
470 $this->getTitle()->getTalkPage()->getFullURL()
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
getWikiPage()
Get a WikiPage object.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
getTitle()
Shortcut to get the Title object from the page.
getContext()
Get the IContextSource in use here.
getOutput()
Get the OutputPage being used for this instance.
getUser()
Shortcut to get the User being used for this instance.
static exists(string $name)
Check if a given action is recognised, even if it's disabled.
getArticle()
Get a Article object.
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
array $fields
The fields used to create the HTMLForm.
getLanguage()
Shortcut to get the user Language being used for this instance.
getAuthority()
Shortcut to get the Authority executing this instance.
getRequest()
Get the WebRequest being used for this instance.
Page view caching in the file system.
static useFileCache(IContextSource $context, $mode=self::MODE_NORMAL)
Check if pages can be cached for this request/user.
This class handles printing the history page for an article.
onView()
Print the history page for an article.
array $message
Array of message keys and strings.
getName()
Return the name of the action this object responds to.
requiresWrite()
Whether this action requires the wiki not to be locked.
getPageTitle()
Returns the name that goes in the <h1> page title.
getDescription()
Returns the description that goes below the <h1> element.
requiresUnblock()
Whether this action can still be executed by a blocked user.
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
static getLocalInstance( $ts=false)
Get a timestamp instance in the server local timezone ($wgLocaltimezone)
A class containing constants representing the names of configuration variables.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
getVal( $name, $default=null)
Fetch a text string and partially normalize it.
getBool( $name, $default=false)
Fetch a boolean value from the input or return $default if not set.
getInt( $name, $default=0)
Fetch an integer value from the input or return $default if not set.
getRawVal( $name, $default=null)
Fetch a string WITHOUT any Unicode or line break normalization.