MediaWiki  1.28.0
EnhancedChangesList.php
Go to the documentation of this file.
1 <?php
24 
28  protected $cacheEntryFactory;
29 
33  protected $rc_cache;
34 
39  public function __construct( $obj ) {
40  if ( $obj instanceof Skin ) {
41  // @todo: deprecate constructing with Skin
42  $context = $obj->getContext();
43  } else {
44  if ( !$obj instanceof IContextSource ) {
45  throw new MWException( 'EnhancedChangesList must be constructed with a '
46  . 'context source or skin.' );
47  }
48 
49  $context = $obj;
50  }
51 
52  parent::__construct( $context );
53 
54  // message is set by the parent ChangesList class
55  $this->cacheEntryFactory = new RCCacheEntryFactory(
56  $context,
57  $this->message,
58  $this->linkRenderer
59  );
60  }
61 
66  public function beginRecentChangesList() {
67  $this->rc_cache = [];
68  $this->rcMoveIndex = 0;
69  $this->rcCacheIndex = 0;
70  $this->lastdate = '';
71  $this->rclistOpen = false;
72  $this->getOutput()->addModuleStyles( [
73  'mediawiki.special.changeslist',
74  'mediawiki.special.changeslist.enhanced',
75  ] );
76  $this->getOutput()->addModules( [
77  'jquery.makeCollapsible',
78  'mediawiki.icon',
79  ] );
80 
81  return '<div class="mw-changeslist">';
82  }
83 
93  public function recentChangesLine( &$rc, $watched = false, $linenumber = null ) {
94 
95  $date = $this->getLanguage()->userDate(
96  $rc->mAttribs['rc_timestamp'],
97  $this->getUser()
98  );
99 
100  $ret = '';
101 
102  # If it's a new day, add the headline and flush the cache
103  if ( $date != $this->lastdate ) {
104  # Process current cache
105  $ret = $this->recentChangesBlock();
106  $this->rc_cache = [];
107  $ret .= Xml::element( 'h4', null, $date ) . "\n";
108  $this->lastdate = $date;
109  }
110 
111  $cacheEntry = $this->cacheEntryFactory->newFromRecentChange( $rc, $watched );
112  $this->addCacheEntry( $cacheEntry );
113 
114  return $ret;
115  }
116 
123  protected function addCacheEntry( RCCacheEntry $cacheEntry ) {
124  $cacheGroupingKey = $this->makeCacheGroupingKey( $cacheEntry );
125 
126  if ( !isset( $this->rc_cache[$cacheGroupingKey] ) ) {
127  $this->rc_cache[$cacheGroupingKey] = [];
128  }
129 
130  array_push( $this->rc_cache[$cacheGroupingKey], $cacheEntry );
131  }
132 
140  protected function makeCacheGroupingKey( RCCacheEntry $cacheEntry ) {
141  $title = $cacheEntry->getTitle();
142  $cacheGroupingKey = $title->getPrefixedDBkey();
143 
144  $type = $cacheEntry->mAttribs['rc_type'];
145 
146  if ( $type == RC_LOG ) {
147  // Group by log type
148  $cacheGroupingKey = SpecialPage::getTitleFor(
149  'Log',
150  $cacheEntry->mAttribs['rc_log_type']
151  )->getPrefixedDBkey();
152  }
153 
154  return $cacheGroupingKey;
155  }
156 
163  protected function recentChangesBlockGroup( $block ) {
164  $recentChangesFlags = $this->getConfig()->get( 'RecentChangesFlags' );
165 
166  # Add the namespace and title of the block as part of the class
167  $tableClasses = [ 'mw-collapsible', 'mw-collapsed', 'mw-enhanced-rc' ];
168  if ( $block[0]->mAttribs['rc_log_type'] ) {
169  # Log entry
170  $tableClasses[] = Sanitizer::escapeClass( 'mw-changeslist-log-'
171  . $block[0]->mAttribs['rc_log_type'] );
172  } else {
173  $tableClasses[] = Sanitizer::escapeClass( 'mw-changeslist-ns'
174  . $block[0]->mAttribs['rc_namespace'] . '-' . $block[0]->mAttribs['rc_title'] );
175  }
176  if ( $block[0]->watched
177  && $block[0]->mAttribs['rc_timestamp'] >= $block[0]->watched
178  ) {
179  $tableClasses[] = 'mw-changeslist-line-watched';
180  } else {
181  $tableClasses[] = 'mw-changeslist-line-not-watched';
182  }
183 
184  # Collate list of users
185  $userlinks = [];
186  # Other properties
187  $curId = 0;
188  # Some catalyst variables...
189  $namehidden = true;
190  $allLogs = true;
191  $RCShowChangedSize = $this->getConfig()->get( 'RCShowChangedSize' );
192 
193  # Default values for RC flags
194  $collectedRcFlags = [];
195  foreach ( $recentChangesFlags as $key => $value ) {
196  $flagGrouping = ( isset( $recentChangesFlags[$key]['grouping'] ) ?
197  $recentChangesFlags[$key]['grouping'] : 'any' );
198  switch ( $flagGrouping ) {
199  case 'all':
200  $collectedRcFlags[$key] = true;
201  break;
202  case 'any':
203  $collectedRcFlags[$key] = false;
204  break;
205  default:
206  throw new DomainException( "Unknown grouping type \"{$flagGrouping}\"" );
207  }
208  }
209  foreach ( $block as $rcObj ) {
210  // If all log actions to this page were hidden, then don't
211  // give the name of the affected page for this block!
212  if ( !$this->isDeleted( $rcObj, LogPage::DELETED_ACTION ) ) {
213  $namehidden = false;
214  }
215  $u = $rcObj->userlink;
216  if ( !isset( $userlinks[$u] ) ) {
217  $userlinks[$u] = 0;
218  }
219  if ( $rcObj->mAttribs['rc_type'] != RC_LOG ) {
220  $allLogs = false;
221  }
222  # Get the latest entry with a page_id and oldid
223  # since logs may not have these.
224  if ( !$curId && $rcObj->mAttribs['rc_cur_id'] ) {
225  $curId = $rcObj->mAttribs['rc_cur_id'];
226  }
227 
228  $userlinks[$u]++;
229  }
230 
231  # Sort the list and convert to text
232  krsort( $userlinks );
233  asort( $userlinks );
234  $users = [];
235  foreach ( $userlinks as $userlink => $count ) {
236  $text = $userlink;
237  $text .= $this->getLanguage()->getDirMark();
238  if ( $count > 1 ) {
239  // @todo FIXME: Hardcoded '×'. Should be a message.
240  $formattedCount = $this->getLanguage()->formatNum( $count ) . '×';
241  $text .= ' ' . $this->msg( 'parentheses' )->rawParams( $formattedCount )->escaped();
242  }
243  array_push( $users, $text );
244  }
245 
246  # Article link
247  $articleLink = '';
248  $revDeletedMsg = false;
249  if ( $namehidden ) {
250  $revDeletedMsg = $this->msg( 'rev-deleted-event' )->escaped();
251  } elseif ( $allLogs ) {
252  $articleLink = $this->maybeWatchedLink( $block[0]->link, $block[0]->watched );
253  } else {
254  $articleLink = $this->getArticleLink( $block[0], $block[0]->unpatrolled, $block[0]->watched );
255  }
256 
257  $queryParams['curid'] = $curId;
258 
259  # Sub-entries
260  $lines = [];
261  foreach ( $block as $i => $rcObj ) {
262  $line = $this->getLineData( $block, $rcObj, $queryParams );
263  if ( !$line ) {
264  // completely ignore this RC entry if we don't want to render it
265  unset( $block[$i] );
266  continue;
267  }
268 
269  // Roll up flags
270  foreach ( $line['recentChangesFlagsRaw'] as $key => $value ) {
271  $flagGrouping = ( isset( $recentChangesFlags[$key]['grouping'] ) ?
272  $recentChangesFlags[$key]['grouping'] : 'any' );
273  switch ( $flagGrouping ) {
274  case 'all':
275  if ( !$value ) {
276  $collectedRcFlags[$key] = false;
277  }
278  break;
279  case 'any':
280  if ( $value ) {
281  $collectedRcFlags[$key] = true;
282  }
283  break;
284  default:
285  throw new DomainException( "Unknown grouping type \"{$flagGrouping}\"" );
286  }
287  }
288 
289  $lines[] = $line;
290  }
291 
292  // Further down are some assumptions that $block is a 0-indexed array
293  // with (count-1) as last key. Let's make sure it is.
294  $block = array_values( $block );
295 
296  if ( empty( $block ) || !$lines ) {
297  // if we can't show anything, don't display this block altogether
298  return '';
299  }
300 
301  $logText = $this->getLogText( $block, $queryParams, $allLogs,
302  $collectedRcFlags['newpage'], $namehidden
303  );
304 
305  # Character difference (does not apply if only log items)
306  $charDifference = false;
307  if ( $RCShowChangedSize && !$allLogs ) {
308  $last = 0;
309  $first = count( $block ) - 1;
310  # Some events (like logs and category changes) have an "empty" size, so we need to skip those...
311  while ( $last < $first && $block[$last]->mAttribs['rc_new_len'] === null ) {
312  $last++;
313  }
314  while ( $last < $first && $block[$first]->mAttribs['rc_old_len'] === null ) {
315  $first--;
316  }
317  # Get net change
318  $charDifference = $this->formatCharacterDifference( $block[$first], $block[$last] );
319  }
320 
321  $numberofWatchingusers = $this->numberofWatchingusers( $block[0]->numberofWatchingusers );
322  $usersList = $this->msg( 'brackets' )->rawParams(
323  implode( $this->message['semicolon-separator'], $users )
324  )->escaped();
325 
326  $templateParams = [
327  'articleLink' => $articleLink,
328  'charDifference' => $charDifference,
329  'collectedRcFlags' => $this->recentChangesFlags( $collectedRcFlags ),
330  'languageDirMark' => $this->getLanguage()->getDirMark(),
331  'lines' => $lines,
332  'logText' => $logText,
333  'numberofWatchingusers' => $numberofWatchingusers,
334  'rev-deleted-event' => $revDeletedMsg,
335  'tableClasses' => $tableClasses,
336  'timestamp' => $block[0]->timestamp,
337  'users' => $usersList,
338  ];
339 
340  $this->rcCacheIndex++;
341 
343  return $templateParser->processTemplate(
344  'EnhancedChangesListGroup',
345  $templateParams
346  );
347  }
348 
358  protected function getLineData( array $block, RCCacheEntry $rcObj, array $queryParams = [] ) {
359  $RCShowChangedSize = $this->getConfig()->get( 'RCShowChangedSize' );
360 
361  $classes = [ 'mw-enhanced-rc' ];
362  $type = $rcObj->mAttribs['rc_type'];
363  $data = [];
364  $lineParams = [];
365 
366  if ( $rcObj->watched
367  && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched
368  ) {
369  $classes = [ 'mw-enhanced-watched' ];
370  }
371 
372  $separator = ' <span class="mw-changeslist-separator">. .</span> ';
373 
374  $data['recentChangesFlags'] = [
375  'newpage' => $type == RC_NEW,
376  'minor' => $rcObj->mAttribs['rc_minor'],
377  'unpatrolled' => $rcObj->unpatrolled,
378  'bot' => $rcObj->mAttribs['rc_bot'],
379  ];
380 
381  $params = $queryParams;
382 
383  if ( $rcObj->mAttribs['rc_this_oldid'] != 0 ) {
384  $params['oldid'] = $rcObj->mAttribs['rc_this_oldid'];
385  }
386 
387  # Log timestamp
388  if ( $type == RC_LOG ) {
389  $link = $rcObj->timestamp;
390  # Revision link
391  } elseif ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ) {
392  $link = '<span class="history-deleted">' . $rcObj->timestamp . '</span> ';
393  } else {
394  $link = $this->linkRenderer->makeKnownLink(
395  $rcObj->getTitle(),
396  new HtmlArmor( $rcObj->timestamp ),
397  [],
398  $params
399  );
400  if ( $this->isDeleted( $rcObj, Revision::DELETED_TEXT ) ) {
401  $link = '<span class="history-deleted">' . $link . '</span> ';
402  }
403  }
404  $data['timestampLink'] = $link;
405 
406  $currentAndLastLinks = '';
407  if ( !$type == RC_LOG || $type == RC_NEW ) {
408  $currentAndLastLinks .= ' ' . $this->msg( 'parentheses' )->rawParams(
409  $rcObj->curlink .
410  $this->message['pipe-separator'] .
411  $rcObj->lastlink
412  )->escaped();
413  }
414  $data['currentAndLastLinks'] = $currentAndLastLinks;
415  $data['separatorAfterCurrentAndLastLinks'] = $separator;
416 
417  # Character diff
418  if ( $RCShowChangedSize ) {
419  $cd = $this->formatCharacterDifference( $rcObj );
420  if ( $cd !== '' ) {
421  $data['characterDiff'] = $cd;
422  $data['separatorAfterCharacterDiff'] = $separator;
423  }
424  }
425 
426  if ( $rcObj->mAttribs['rc_type'] == RC_LOG ) {
427  $data['logEntry'] = $this->insertLogEntry( $rcObj );
428  } elseif ( $this->isCategorizationWithoutRevision( $rcObj ) ) {
429  $data['comment'] = $this->insertComment( $rcObj );
430  } else {
431  # User links
432  $data['userLink'] = $rcObj->userlink;
433  $data['userTalkLink'] = $rcObj->usertalklink;
434  $data['comment'] = $this->insertComment( $rcObj );
435  }
436 
437  # Rollback
438  $data['rollback'] = $this->getRollback( $rcObj );
439 
440  # Tags
441  $data['tags'] = $this->getTags( $rcObj, $classes );
442 
443  // give the hook a chance to modify the data
444  $success = Hooks::run( 'EnhancedChangesListModifyLineData',
445  [ $this, &$data, $block, $rcObj, &$classes ] );
446  if ( !$success ) {
447  // skip entry if hook aborted it
448  return [];
449  }
450 
451  $lineParams['recentChangesFlagsRaw'] = [];
452  if ( isset( $data['recentChangesFlags'] ) ) {
453  $lineParams['recentChangesFlags'] = $this->recentChangesFlags( $data['recentChangesFlags'] );
454  # FIXME: This is used by logic, don't return it in the template params.
455  $lineParams['recentChangesFlagsRaw'] = $data['recentChangesFlags'];
456  unset( $data['recentChangesFlags'] );
457  }
458 
459  if ( isset( $data['timestampLink'] ) ) {
460  $lineParams['timestampLink'] = $data['timestampLink'];
461  unset( $data['timestampLink'] );
462  }
463 
464  $lineParams['classes'] = array_values( $classes );
465 
466  // everything else: makes it easier for extensions to add or remove data
467  $lineParams['data'] = array_values( $data );
468 
469  return $lineParams;
470  }
471 
482  protected function getLogText( $block, $queryParams, $allLogs, $isnew, $namehidden ) {
483  if ( empty( $block ) ) {
484  return '';
485  }
486 
487  # Changes message
488  static $nchanges = [];
489  static $sinceLastVisitMsg = [];
490 
491  $n = count( $block );
492  if ( !isset( $nchanges[$n] ) ) {
493  $nchanges[$n] = $this->msg( 'nchanges' )->numParams( $n )->escaped();
494  }
495 
496  $sinceLast = 0;
497  $unvisitedOldid = null;
499  foreach ( $block as $rcObj ) {
500  // Same logic as below inside main foreach
501  if ( $rcObj->watched && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched ) {
502  $sinceLast++;
503  $unvisitedOldid = $rcObj->mAttribs['rc_last_oldid'];
504  }
505  }
506  if ( !isset( $sinceLastVisitMsg[$sinceLast] ) ) {
507  $sinceLastVisitMsg[$sinceLast] =
508  $this->msg( 'enhancedrc-since-last-visit' )->numParams( $sinceLast )->escaped();
509  }
510 
511  $currentRevision = 0;
512  foreach ( $block as $rcObj ) {
513  if ( !$currentRevision ) {
514  $currentRevision = $rcObj->mAttribs['rc_this_oldid'];
515  }
516  }
517 
518  # Total change link
519  $links = [];
521  $block0 = $block[0];
522  $last = $block[count( $block ) - 1];
523  if ( !$allLogs ) {
524  if ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ||
525  $isnew ||
526  $rcObj->mAttribs['rc_type'] == RC_CATEGORIZE
527  ) {
528  $links['total-changes'] = $nchanges[$n];
529  } else {
530  $links['total-changes'] = $this->linkRenderer->makeKnownLink(
531  $block0->getTitle(),
532  new HtmlArmor( $nchanges[$n] ),
533  [],
534  $queryParams + [
535  'diff' => $currentRevision,
536  'oldid' => $last->mAttribs['rc_last_oldid'],
537  ]
538  );
539  if ( $sinceLast > 0 && $sinceLast < $n ) {
540  $links['total-changes-since-last'] = $this->linkRenderer->makeKnownLink(
541  $block0->getTitle(),
542  new HtmlArmor( $sinceLastVisitMsg[$sinceLast] ),
543  [],
544  $queryParams + [
545  'diff' => $currentRevision,
546  'oldid' => $unvisitedOldid,
547  ]
548  );
549  }
550  }
551  }
552 
553  # History
554  if ( $allLogs || $rcObj->mAttribs['rc_type'] == RC_CATEGORIZE ) {
555  // don't show history link for logs
556  } elseif ( $namehidden || !$block0->getTitle()->exists() ) {
557  $links['history'] = $this->message['enhancedrc-history'];
558  } else {
559  $params = $queryParams;
560  $params['action'] = 'history';
561 
562  $links['history'] = $this->linkRenderer->makeKnownLink(
563  $block0->getTitle(),
564  new HtmlArmor( $this->message['enhancedrc-history'] ),
565  [],
566  $params
567  );
568  }
569 
570  # Allow others to alter, remove or add to these links
571  Hooks::run( 'EnhancedChangesList::getLogText',
572  [ $this, &$links, $block ] );
573 
574  if ( !$links ) {
575  return '';
576  }
577 
578  $logtext = implode( $this->message['pipe-separator'], $links );
579  $logtext = $this->msg( 'parentheses' )->rawParams( $logtext )->escaped();
580  return ' ' . $logtext;
581  }
582 
589  protected function recentChangesBlockLine( $rcObj ) {
590  $data = [];
591 
592  $query['curid'] = $rcObj->mAttribs['rc_cur_id'];
593 
594  $type = $rcObj->mAttribs['rc_type'];
595  $logType = $rcObj->mAttribs['rc_log_type'];
596  $classes = $this->getHTMLClasses( $rcObj, $rcObj->watched );
597  $classes[] = 'mw-enhanced-rc';
598 
599  if ( $logType ) {
600  # Log entry
601  $classes[] = Sanitizer::escapeClass( 'mw-changeslist-log-' . $logType );
602  } else {
603  $classes[] = Sanitizer::escapeClass( 'mw-changeslist-ns' .
604  $rcObj->mAttribs['rc_namespace'] . '-' . $rcObj->mAttribs['rc_title'] );
605  }
606 
607  # Flag and Timestamp
608  $data['recentChangesFlags'] = [
609  'newpage' => $type == RC_NEW,
610  'minor' => $rcObj->mAttribs['rc_minor'],
611  'unpatrolled' => $rcObj->unpatrolled,
612  'bot' => $rcObj->mAttribs['rc_bot'],
613  ];
614  // timestamp is not really a link here, but is called timestampLink
615  // for consistency with EnhancedChangesListModifyLineData
616  $data['timestampLink'] = $rcObj->timestamp;
617 
618  # Article or log link
619  if ( $logType ) {
620  $logPage = new LogPage( $logType );
621  $logTitle = SpecialPage::getTitleFor( 'Log', $logType );
622  $logName = $logPage->getName()->text();
623  $data['logLink'] = $this->msg( 'parentheses' )
624  ->rawParams(
625  $this->linkRenderer->makeKnownLink( $logTitle, $logName )
626  )->escaped();
627  } else {
628  $data['articleLink'] = $this->getArticleLink( $rcObj, $rcObj->unpatrolled, $rcObj->watched );
629  }
630 
631  # Diff and hist links
632  if ( $type != RC_LOG && $type != RC_CATEGORIZE ) {
633  $query['action'] = 'history';
634  $data['historyLink'] = $this->getDiffHistLinks( $rcObj, $query );
635  }
636  $data['separatorAfterLinks'] = ' <span class="mw-changeslist-separator">. .</span> ';
637 
638  # Character diff
639  if ( $this->getConfig()->get( 'RCShowChangedSize' ) ) {
640  $cd = $this->formatCharacterDifference( $rcObj );
641  if ( $cd !== '' ) {
642  $data['characterDiff'] = $cd;
643  $data['separatorAftercharacterDiff'] = ' <span class="mw-changeslist-separator">. .</span> ';
644  }
645  }
646 
647  if ( $type == RC_LOG ) {
648  $data['logEntry'] = $this->insertLogEntry( $rcObj );
649  } elseif ( $this->isCategorizationWithoutRevision( $rcObj ) ) {
650  $data['comment'] = $this->insertComment( $rcObj );
651  } else {
652  $data['userLink'] = $rcObj->userlink;
653  $data['userTalkLink'] = $rcObj->usertalklink;
654  $data['comment'] = $this->insertComment( $rcObj );
655  if ( $type == RC_CATEGORIZE ) {
656  $data['historyLink'] = $this->getDiffHistLinks( $rcObj, $query );
657  }
658  $data['rollback'] = $this->getRollback( $rcObj );
659  }
660 
661  # Tags
662  $data['tags'] = $this->getTags( $rcObj, $classes );
663 
664  # Show how many people are watching this if enabled
665  $data['watchingUsers'] = $this->numberofWatchingusers( $rcObj->numberofWatchingusers );
666 
667  // give the hook a chance to modify the data
668  $success = Hooks::run( 'EnhancedChangesListModifyBlockLineData',
669  [ $this, &$data, $rcObj ] );
670  if ( !$success ) {
671  // skip entry if hook aborted it
672  return '';
673  }
674 
675  $line = Html::openElement( 'table', [ 'class' => $classes ] ) .
676  Html::openElement( 'tr' );
677  $line .= '<td class="mw-enhanced-rc"><span class="mw-enhancedchanges-arrow-space"></span>';
678 
679  if ( isset( $data['recentChangesFlags'] ) ) {
680  $line .= $this->recentChangesFlags( $data['recentChangesFlags'] );
681  unset( $data['recentChangesFlags'] );
682  }
683 
684  if ( isset( $data['timestampLink'] ) ) {
685  $line .= '&#160;' . $data['timestampLink'];
686  unset( $data['timestampLink'] );
687  }
688  $line .= '&#160;</td><td>';
689 
690  // everything else: makes it easier for extensions to add or remove data
691  $line .= implode( '', $data );
692 
693  $line .= "</td></tr></table>\n";
694 
695  return $line;
696  }
697 
708  public function getDiffHistLinks( RCCacheEntry $rc, array $query ) {
709  $pageTitle = $rc->getTitle();
710  if ( $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE ) {
711  // For categorizations we must swap the category title with the page title!
712  $pageTitle = Title::newFromID( $rc->getAttribute( 'rc_cur_id' ) );
713  }
714 
715  $retVal = ' ' . $this->msg( 'parentheses' )
716  ->rawParams( $rc->difflink . $this->message['pipe-separator']
717  . $this->linkRenderer->makeKnownLink(
718  $pageTitle,
719  new HtmlArmor( $this->message['hist'] ),
720  [],
721  $query
722  ) )->escaped();
723  return $retVal;
724  }
725 
732  protected function recentChangesBlock() {
733  if ( count( $this->rc_cache ) == 0 ) {
734  return '';
735  }
736 
737  $blockOut = '';
738  foreach ( $this->rc_cache as $block ) {
739  if ( count( $block ) < 2 ) {
740  $blockOut .= $this->recentChangesBlockLine( array_shift( $block ) );
741  } else {
742  $blockOut .= $this->recentChangesBlockGroup( $block );
743  }
744  }
745 
746  return '<div>' . $blockOut . '</div>';
747  }
748 
754  public function endRecentChangesList() {
755  return $this->recentChangesBlock() . '</div>';
756  }
757 }
static newFromID($id, $flags=0)
Create a new Title from an article ID.
Definition: Title.php:402
const RC_CATEGORIZE
Definition: Defines.php:140
Interface for objects which can provide a MediaWiki context on request.
static userCan($rc, $field, User $user=null)
Determine if the current user is allowed to view a particular field of this revision, if it's marked as deleted.
the array() calling protocol came about after MediaWiki 1.4rc1.
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1555
getLanguage()
Get the Language object.
The main skin class which provides methods and properties for all other skins.
Definition: Skin.php:34
getLogText($block, $queryParams, $allLogs, $isnew, $namehidden)
Generates amount of changes (linking to diff ) & link to history.
static element($element, $attribs=null, $contents= '', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:39
$success
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1936
recentChangesFlags($flags, $nothing= '&#160;')
Returns the appropriate flags for new page, minor change and patrolling.
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...
Definition: SpecialPage.php:82
static isDeleted($rc, $field)
Determine if said field of a revision is hidden.
getTags(RecentChange $rc, array &$classes)
$value
numberofWatchingusers($count)
Returns the string which indicates the number of watching users.
formatCharacterDifference(RecentChange $old, RecentChange $new=null)
Format the character difference of one or several changes.
static escapeClass($class)
Given a value, escape it so that it can be used as a CSS class and return it.
Definition: Sanitizer.php:1247
IContextSource $context
getDiffHistLinks(RCCacheEntry $rc, array $query)
Returns value to be used in 'historyLink' element of $data param in EnhancedChangesListModifyBlockLin...
getAttribute($name)
Get an attribute value.
recentChangesBlockGroup($block)
Enhanced RC group.
Class to simplify the use of log pages.
Definition: LogPage.php:32
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition: hooks.txt:2889
$last
msg()
Get a Message object with context set Parameters are the same as wfMessage()
static openElement($element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition: Html.php:247
RCCacheEntryFactory $cacheEntryFactory
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a message
Definition: hooks.txt:2094
getLineData(array $block, RCCacheEntry $rcObj, array $queryParams=[])
getConfig()
Get the Config object.
getRollback(RecentChange $rc)
getArticleLink(&$rc, $unpatrolled, $watched)
$params
array $rc_cache
Array of array of RCCacheEntry.
makeCacheGroupingKey(RCCacheEntry $cacheEntry)
recentChangesBlock()
If enhanced RC is in use, this function takes the previously cached RC lines, arranges them...
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:953
isCategorizationWithoutRevision($rcObj)
Determines whether a revision is linked to this change; this may not be the case when the categorizat...
static run($event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:131
beginRecentChangesList()
Add the JavaScript file for enhanced changeslist.
recentChangesBlockLine($rcObj)
Enhanced RC ungrouped line.
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
const DELETED_TEXT
Definition: Revision.php:85
endRecentChangesList()
Returns text for the end of RC If enhanced RC is in use, returns pretty much all the text...
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
addCacheEntry(RCCacheEntry $cacheEntry)
Put accumulated information into the cache, for later display.
$lines
Definition: router.php:67
$line
Definition: cdb.php:59
usually copyright or history_copyright This message must be in HTML not wikitext if the section is included from a template to be included in the link
Definition: hooks.txt:2889
insertLogEntry($rc)
Insert a formatted action.
$count
$templateParser
const RC_NEW
Definition: Defines.php:137
const DELETED_ACTION
Definition: LogPage.php:33
insertComment($rc)
Insert a formatted comment.
getHTMLClasses($rc, $watched)
Get an array of default HTML class attributes for the change.
recentChangesLine(&$rc, $watched=false, $linenumber=null)
Format a line for enhanced recentchange (aka with javascript and block of lines). ...
getUser()
Get the User object.
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect as a string mapping parameter names to values & $type
Definition: hooks.txt:2491
maybeWatchedLink($link, $watched=false)
const RC_LOG
Definition: Defines.php:138
getOutput()
Get the OutputPage object.