MediaWiki  1.27.2
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  );
59  }
60 
65  public function beginRecentChangesList() {
66  $this->rc_cache = [];
67  $this->rcMoveIndex = 0;
68  $this->rcCacheIndex = 0;
69  $this->lastdate = '';
70  $this->rclistOpen = false;
71  $this->getOutput()->addModuleStyles( [
72  'mediawiki.special.changeslist',
73  'mediawiki.special.changeslist.enhanced',
74  ] );
75  $this->getOutput()->addModules( [
76  'jquery.makeCollapsible',
77  'mediawiki.icon',
78  ] );
79 
80  return '<div class="mw-changeslist">';
81  }
82 
92  public function recentChangesLine( &$rc, $watched = false, $linenumber = null ) {
93 
94  $date = $this->getLanguage()->userDate(
95  $rc->mAttribs['rc_timestamp'],
96  $this->getUser()
97  );
98 
99  $ret = '';
100 
101  # If it's a new day, add the headline and flush the cache
102  if ( $date != $this->lastdate ) {
103  # Process current cache
104  $ret = $this->recentChangesBlock();
105  $this->rc_cache = [];
106  $ret .= Xml::element( 'h4', null, $date ) . "\n";
107  $this->lastdate = $date;
108  }
109 
110  $cacheEntry = $this->cacheEntryFactory->newFromRecentChange( $rc, $watched );
111  $this->addCacheEntry( $cacheEntry );
112 
113  return $ret;
114  }
115 
122  protected function addCacheEntry( RCCacheEntry $cacheEntry ) {
123  $cacheGroupingKey = $this->makeCacheGroupingKey( $cacheEntry );
124 
125  if ( !isset( $this->rc_cache[$cacheGroupingKey] ) ) {
126  $this->rc_cache[$cacheGroupingKey] = [];
127  }
128 
129  array_push( $this->rc_cache[$cacheGroupingKey], $cacheEntry );
130  }
131 
139  protected function makeCacheGroupingKey( RCCacheEntry $cacheEntry ) {
140  $title = $cacheEntry->getTitle();
141  $cacheGroupingKey = $title->getPrefixedDBkey();
142 
143  $type = $cacheEntry->mAttribs['rc_type'];
144 
145  if ( $type == RC_LOG ) {
146  // Group by log type
147  $cacheGroupingKey = SpecialPage::getTitleFor(
148  'Log',
149  $cacheEntry->mAttribs['rc_log_type']
150  )->getPrefixedDBkey();
151  }
152 
153  return $cacheGroupingKey;
154  }
155 
162  protected function recentChangesBlockGroup( $block ) {
163  $recentChangesFlags = $this->getConfig()->get( 'RecentChangesFlags' );
164 
165  # Add the namespace and title of the block as part of the class
166  $tableClasses = [ 'mw-collapsible', 'mw-collapsed', 'mw-enhanced-rc' ];
167  if ( $block[0]->mAttribs['rc_log_type'] ) {
168  # Log entry
169  $tableClasses[] = Sanitizer::escapeClass( 'mw-changeslist-log-'
170  . $block[0]->mAttribs['rc_log_type'] );
171  } else {
172  $tableClasses[] = Sanitizer::escapeClass( 'mw-changeslist-ns'
173  . $block[0]->mAttribs['rc_namespace'] . '-' . $block[0]->mAttribs['rc_title'] );
174  }
175  if ( $block[0]->watched
176  && $block[0]->mAttribs['rc_timestamp'] >= $block[0]->watched
177  ) {
178  $tableClasses[] = 'mw-changeslist-line-watched';
179  } else {
180  $tableClasses[] = 'mw-changeslist-line-not-watched';
181  }
182 
183  # Collate list of users
184  $userlinks = [];
185  # Other properties
186  $curId = 0;
187  # Some catalyst variables...
188  $namehidden = true;
189  $allLogs = true;
190  $RCShowChangedSize = $this->getConfig()->get( 'RCShowChangedSize' );
191 
192  # Default values for RC flags
193  $collectedRcFlags = [];
194  foreach ( $recentChangesFlags as $key => $value ) {
195  $flagGrouping = ( isset( $recentChangesFlags[$key]['grouping'] ) ?
196  $recentChangesFlags[$key]['grouping'] : 'any' );
197  switch ( $flagGrouping ) {
198  case 'all':
199  $collectedRcFlags[$key] = true;
200  break;
201  case 'any':
202  $collectedRcFlags[$key] = false;
203  break;
204  default:
205  throw new DomainException( "Unknown grouping type \"{$flagGrouping}\"" );
206  }
207  }
208  foreach ( $block as $rcObj ) {
209  // If all log actions to this page were hidden, then don't
210  // give the name of the affected page for this block!
211  if ( !$this->isDeleted( $rcObj, LogPage::DELETED_ACTION ) ) {
212  $namehidden = false;
213  }
214  $u = $rcObj->userlink;
215  if ( !isset( $userlinks[$u] ) ) {
216  $userlinks[$u] = 0;
217  }
218  if ( $rcObj->mAttribs['rc_type'] != RC_LOG ) {
219  $allLogs = false;
220  }
221  # Get the latest entry with a page_id and oldid
222  # since logs may not have these.
223  if ( !$curId && $rcObj->mAttribs['rc_cur_id'] ) {
224  $curId = $rcObj->mAttribs['rc_cur_id'];
225  }
226 
227  $userlinks[$u]++;
228  }
229 
230  # Sort the list and convert to text
231  krsort( $userlinks );
232  asort( $userlinks );
233  $users = [];
234  foreach ( $userlinks as $userlink => $count ) {
235  $text = $userlink;
236  $text .= $this->getLanguage()->getDirMark();
237  if ( $count > 1 ) {
238  // @todo FIXME: Hardcoded '×'. Should be a message.
239  $formattedCount = $this->getLanguage()->formatNum( $count ) . '×';
240  $text .= ' ' . $this->msg( 'parentheses' )->rawParams( $formattedCount )->escaped();
241  }
242  array_push( $users, $text );
243  }
244 
245  # Article link
246  $articleLink = '';
247  $revDeletedMsg = false;
248  if ( $namehidden ) {
249  $revDeletedMsg = $this->msg( 'rev-deleted-event' )->escaped();
250  } elseif ( $allLogs ) {
251  $articleLink = $this->maybeWatchedLink( $block[0]->link, $block[0]->watched );
252  } else {
253  $articleLink = $this->getArticleLink( $block[0], $block[0]->unpatrolled, $block[0]->watched );
254  }
255 
256  $queryParams['curid'] = $curId;
257 
258  # Sub-entries
259  $lines = [];
260  foreach ( $block as $i => $rcObj ) {
261  $line = $this->getLineData( $block, $rcObj, $queryParams );
262  if ( !$line ) {
263  // completely ignore this RC entry if we don't want to render it
264  unset( $block[$i] );
265  continue;
266  }
267 
268  // Roll up flags
269  foreach ( $line['recentChangesFlagsRaw'] as $key => $value ) {
270  $flagGrouping = ( isset( $recentChangesFlags[$key]['grouping'] ) ?
271  $recentChangesFlags[$key]['grouping'] : 'any' );
272  switch ( $flagGrouping ) {
273  case 'all':
274  if ( !$value ) {
275  $collectedRcFlags[$key] = false;
276  }
277  break;
278  case 'any':
279  if ( $value ) {
280  $collectedRcFlags[$key] = true;
281  }
282  break;
283  default:
284  throw new DomainException( "Unknown grouping type \"{$flagGrouping}\"" );
285  }
286  }
287 
288  $lines[] = $line;
289  }
290 
291  // Further down are some assumptions that $block is a 0-indexed array
292  // with (count-1) as last key. Let's make sure it is.
293  $block = array_values( $block );
294 
295  if ( empty( $block ) || !$lines ) {
296  // if we can't show anything, don't display this block altogether
297  return '';
298  }
299 
300  $logText = $this->getLogText( $block, $queryParams, $allLogs,
301  $collectedRcFlags['newpage'], $namehidden
302  );
303 
304  # Character difference (does not apply if only log items)
305  $charDifference = false;
306  if ( $RCShowChangedSize && !$allLogs ) {
307  $last = 0;
308  $first = count( $block ) - 1;
309  # Some events (like logs and category changes) have an "empty" size, so we need to skip those...
310  while ( $last < $first && $block[$last]->mAttribs['rc_new_len'] === null ) {
311  $last++;
312  }
313  while ( $last < $first && $block[$first]->mAttribs['rc_old_len'] === null ) {
314  $first--;
315  }
316  # Get net change
317  $charDifference = $this->formatCharacterDifference( $block[$first], $block[$last] );
318  }
319 
320  $numberofWatchingusers = $this->numberofWatchingusers( $block[0]->numberofWatchingusers );
321  $usersList = $this->msg( 'brackets' )->rawParams(
322  implode( $this->message['semicolon-separator'], $users )
323  )->escaped();
324 
325  $templateParams = [
326  'articleLink' => $articleLink,
327  'charDifference' => $charDifference,
328  'collectedRcFlags' => $this->recentChangesFlags( $collectedRcFlags ),
329  'languageDirMark' => $this->getLanguage()->getDirMark(),
330  'lines' => $lines,
331  'logText' => $logText,
332  'numberofWatchingusers' => $numberofWatchingusers,
333  'rev-deleted-event' => $revDeletedMsg,
334  'tableClasses' => $tableClasses,
335  'timestamp' => $block[0]->timestamp,
336  'users' => $usersList,
337  ];
338 
339  $this->rcCacheIndex++;
340 
342  return $templateParser->processTemplate(
343  'EnhancedChangesListGroup',
344  $templateParams
345  );
346  }
347 
357  protected function getLineData( array $block, RCCacheEntry $rcObj, array $queryParams = [] ) {
358  $RCShowChangedSize = $this->getConfig()->get( 'RCShowChangedSize' );
359 
360  # Classes to apply -- TODO implement
361  $classes = [];
362  $type = $rcObj->mAttribs['rc_type'];
363  $data = [];
364  $lineParams = [];
365 
366  if ( $rcObj->watched
367  && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched
368  ) {
369  $lineParams['classes'] = [ 'mw-enhanced-watched' ];
370  }
371  $separator = ' <span class="mw-changeslist-separator">. .</span> ';
372 
373  $data['recentChangesFlags'] = [
374  'newpage' => $type == RC_NEW,
375  'minor' => $rcObj->mAttribs['rc_minor'],
376  'unpatrolled' => $rcObj->unpatrolled,
377  'bot' => $rcObj->mAttribs['rc_bot'],
378  ];
379 
380  $params = $queryParams;
381 
382  if ( $rcObj->mAttribs['rc_this_oldid'] != 0 ) {
383  $params['oldid'] = $rcObj->mAttribs['rc_this_oldid'];
384  }
385 
386  # Log timestamp
387  if ( $type == RC_LOG ) {
388  $link = $rcObj->timestamp;
389  # Revision link
390  } elseif ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ) {
391  $link = '<span class="history-deleted">' . $rcObj->timestamp . '</span> ';
392  } else {
394  $rcObj->getTitle(),
395  $rcObj->timestamp,
396  [],
397  $params
398  );
399  if ( $this->isDeleted( $rcObj, Revision::DELETED_TEXT ) ) {
400  $link = '<span class="history-deleted">' . $link . '</span> ';
401  }
402  }
403  $data['timestampLink'] = $link;
404 
405  $currentAndLastLinks = '';
406  if ( !$type == RC_LOG || $type == RC_NEW ) {
407  $currentAndLastLinks .= ' ' . $this->msg( 'parentheses' )->rawParams(
408  $rcObj->curlink .
409  $this->message['pipe-separator'] .
410  $rcObj->lastlink
411  )->escaped();
412  }
413  $data['currentAndLastLinks'] = $currentAndLastLinks;
414  $data['separatorAfterCurrentAndLastLinks'] = $separator;
415 
416  # Character diff
417  if ( $RCShowChangedSize ) {
418  $cd = $this->formatCharacterDifference( $rcObj );
419  if ( $cd !== '' ) {
420  $data['characterDiff'] = $cd;
421  $data['separatorAfterCharacterDiff'] = $separator;
422  }
423  }
424 
425  if ( $rcObj->mAttribs['rc_type'] == RC_LOG ) {
426  $data['logEntry'] = $this->insertLogEntry( $rcObj );
427  } elseif ( $this->isCategorizationWithoutRevision( $rcObj ) ) {
428  $data['comment'] = $this->insertComment( $rcObj );
429  } else {
430  # User links
431  $data['userLink'] = $rcObj->userlink;
432  $data['userTalkLink'] = $rcObj->usertalklink;
433  $data['comment'] = $this->insertComment( $rcObj );
434  }
435 
436  # Rollback
437  $data['rollback'] = $this->getRollback( $rcObj );
438 
439  # Tags
440  $data['tags'] = $this->getTags( $rcObj, $classes );
441 
442  // give the hook a chance to modify the data
443  $success = Hooks::run( 'EnhancedChangesListModifyLineData',
444  [ $this, &$data, $block, $rcObj ] );
445  if ( !$success ) {
446  // skip entry if hook aborted it
447  return [];
448  }
449 
450  $lineParams['recentChangesFlagsRaw'] = [];
451  if ( isset( $data['recentChangesFlags'] ) ) {
452  $lineParams['recentChangesFlags'] = $this->recentChangesFlags( $data['recentChangesFlags'] );
453  # FIXME: This is used by logic, don't return it in the template params.
454  $lineParams['recentChangesFlagsRaw'] = $data['recentChangesFlags'];
455  unset( $data['recentChangesFlags'] );
456  }
457 
458  if ( isset( $data['timestampLink'] ) ) {
459  $lineParams['timestampLink'] = $data['timestampLink'];
460  unset( $data['timestampLink'] );
461  }
462 
463  // everything else: makes it easier for extensions to add or remove data
464  $lineParams['data'] = array_values( $data );
465 
466  return $lineParams;
467  }
468 
479  protected function getLogText( $block, $queryParams, $allLogs, $isnew, $namehidden ) {
480  if ( empty( $block ) ) {
481  return '';
482  }
483 
484  # Changes message
485  static $nchanges = [];
486  static $sinceLastVisitMsg = [];
487 
488  $n = count( $block );
489  if ( !isset( $nchanges[$n] ) ) {
490  $nchanges[$n] = $this->msg( 'nchanges' )->numParams( $n )->escaped();
491  }
492 
493  $sinceLast = 0;
494  $unvisitedOldid = null;
496  foreach ( $block as $rcObj ) {
497  // Same logic as below inside main foreach
498  if ( $rcObj->watched && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched ) {
499  $sinceLast++;
500  $unvisitedOldid = $rcObj->mAttribs['rc_last_oldid'];
501  }
502  }
503  if ( !isset( $sinceLastVisitMsg[$sinceLast] ) ) {
504  $sinceLastVisitMsg[$sinceLast] =
505  $this->msg( 'enhancedrc-since-last-visit' )->numParams( $sinceLast )->escaped();
506  }
507 
508  $currentRevision = 0;
509  foreach ( $block as $rcObj ) {
510  if ( !$currentRevision ) {
511  $currentRevision = $rcObj->mAttribs['rc_this_oldid'];
512  }
513  }
514 
515  # Total change link
516  $links = [];
518  $block0 = $block[0];
519  $last = $block[count( $block ) - 1];
520  if ( !$allLogs ) {
521  if ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ||
522  $isnew ||
523  $rcObj->mAttribs['rc_type'] == RC_CATEGORIZE
524  ) {
525  $links['total-changes'] = $nchanges[$n];
526  } else {
527  $links['total-changes'] = Linker::link(
528  $block0->getTitle(),
529  $nchanges[$n],
530  [],
531  $queryParams + [
532  'diff' => $currentRevision,
533  'oldid' => $last->mAttribs['rc_last_oldid'],
534  ],
535  [ 'known', 'noclasses' ]
536  );
537  if ( $sinceLast > 0 && $sinceLast < $n ) {
538  $links['total-changes-since-last'] = Linker::link(
539  $block0->getTitle(),
540  $sinceLastVisitMsg[$sinceLast],
541  [],
542  $queryParams + [
543  'diff' => $currentRevision,
544  'oldid' => $unvisitedOldid,
545  ],
546  [ 'known', 'noclasses' ]
547  );
548  }
549  }
550  }
551 
552  # History
553  if ( $allLogs || $rcObj->mAttribs['rc_type'] == RC_CATEGORIZE ) {
554  // don't show history link for logs
555  } elseif ( $namehidden || !$block0->getTitle()->exists() ) {
556  $links['history'] = $this->message['enhancedrc-history'];
557  } else {
558  $params = $queryParams;
559  $params['action'] = 'history';
560 
561  $links['history'] = Linker::linkKnown(
562  $block0->getTitle(),
563  $this->message['enhancedrc-history'],
564  [],
565  $params
566  );
567  }
568 
569  # Allow others to alter, remove or add to these links
570  Hooks::run( 'EnhancedChangesList::getLogText',
571  [ $this, &$links, $block ] );
572 
573  if ( !$links ) {
574  return '';
575  }
576 
577  $logtext = implode( $this->message['pipe-separator'], $links );
578  $logtext = $this->msg( 'parentheses' )->rawParams( $logtext )->escaped();
579  return ' ' . $logtext;
580  }
581 
588  protected function recentChangesBlockLine( $rcObj ) {
589  $data = [];
590 
591  $query['curid'] = $rcObj->mAttribs['rc_cur_id'];
592 
593  $type = $rcObj->mAttribs['rc_type'];
594  $logType = $rcObj->mAttribs['rc_log_type'];
595  $classes = $this->getHTMLClasses( $rcObj, $rcObj->watched );
596  $classes[] = 'mw-enhanced-rc';
597 
598  if ( $logType ) {
599  # Log entry
600  $classes[] = Sanitizer::escapeClass( 'mw-changeslist-log-' . $logType );
601  } else {
602  $classes[] = Sanitizer::escapeClass( 'mw-changeslist-ns' .
603  $rcObj->mAttribs['rc_namespace'] . '-' . $rcObj->mAttribs['rc_title'] );
604  }
605 
606  # Flag and Timestamp
607  $data['recentChangesFlags'] = [
608  'newpage' => $type == RC_NEW,
609  'minor' => $rcObj->mAttribs['rc_minor'],
610  'unpatrolled' => $rcObj->unpatrolled,
611  'bot' => $rcObj->mAttribs['rc_bot'],
612  ];
613  // timestamp is not really a link here, but is called timestampLink
614  // for consistency with EnhancedChangesListModifyLineData
615  $data['timestampLink'] = $rcObj->timestamp;
616 
617  # Article or log link
618  if ( $logType ) {
619  $logPage = new LogPage( $logType );
620  $logTitle = SpecialPage::getTitleFor( 'Log', $logType );
621  $logName = $logPage->getName()->escaped();
622  $data['logLink'] = $this->msg( 'parentheses' )
623  ->rawParams( Linker::linkKnown( $logTitle, $logName ) )->escaped();
624  } else {
625  $data['articleLink'] = $this->getArticleLink( $rcObj, $rcObj->unpatrolled, $rcObj->watched );
626  }
627 
628  # Diff and hist links
629  if ( $type != RC_LOG && $type != RC_CATEGORIZE ) {
630  $query['action'] = 'history';
631  $data['historyLink'] = $this->getDiffHistLinks( $rcObj, $query );
632  }
633  $data['separatorAfterLinks'] = ' <span class="mw-changeslist-separator">. .</span> ';
634 
635  # Character diff
636  if ( $this->getConfig()->get( 'RCShowChangedSize' ) ) {
637  $cd = $this->formatCharacterDifference( $rcObj );
638  if ( $cd !== '' ) {
639  $data['characterDiff'] = $cd;
640  $data['separatorAftercharacterDiff'] = ' <span class="mw-changeslist-separator">. .</span> ';
641  }
642  }
643 
644  if ( $type == RC_LOG ) {
645  $data['logEntry'] = $this->insertLogEntry( $rcObj );
646  } elseif ( $this->isCategorizationWithoutRevision( $rcObj ) ) {
647  $data['comment'] = $this->insertComment( $rcObj );
648  } else {
649  $data['userLink'] = $rcObj->userlink;
650  $data['userTalkLink'] = $rcObj->usertalklink;
651  $data['comment'] = $this->insertComment( $rcObj );
652  if ( $type == RC_CATEGORIZE ) {
653  $data['historyLink'] = $this->getDiffHistLinks( $rcObj, $query );
654  }
655  $data['rollback'] = $this->getRollback( $rcObj );
656  }
657 
658  # Tags
659  $data['tags'] = $this->getTags( $rcObj, $classes );
660 
661  # Show how many people are watching this if enabled
662  $data['watchingUsers'] = $this->numberofWatchingusers( $rcObj->numberofWatchingusers );
663 
664  // give the hook a chance to modify the data
665  $success = Hooks::run( 'EnhancedChangesListModifyBlockLineData',
666  [ $this, &$data, $rcObj ] );
667  if ( !$success ) {
668  // skip entry if hook aborted it
669  return '';
670  }
671 
672  $line = Html::openElement( 'table', [ 'class' => $classes ] ) .
673  Html::openElement( 'tr' );
674  $line .= '<td class="mw-enhanced-rc"><span class="mw-enhancedchanges-arrow-space"></span>';
675 
676  if ( isset( $data['recentChangesFlags'] ) ) {
677  $line .= $this->recentChangesFlags( $data['recentChangesFlags'] );
678  unset( $data['recentChangesFlags'] );
679  }
680 
681  if ( isset( $data['timestampLink'] ) ) {
682  $line .= '&#160;' . $data['timestampLink'];
683  unset( $data['timestampLink'] );
684  }
685  $line .= '&#160;</td><td>';
686 
687  // everything else: makes it easier for extensions to add or remove data
688  $line .= implode( '', $data );
689 
690  $line .= "</td></tr></table>\n";
691 
692  return $line;
693  }
694 
705  public function getDiffHistLinks( RCCacheEntry $rc, array $query ) {
706  $pageTitle = $rc->getTitle();
707  if ( $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE ) {
708  // For categorizations we must swap the category title with the page title!
709  $pageTitle = Title::newFromID( $rc->getAttribute( 'rc_cur_id' ) );
710  }
711 
712  $retVal = ' ' . $this->msg( 'parentheses' )
713  ->rawParams( $rc->difflink . $this->message['pipe-separator'] . Linker::linkKnown(
714  $pageTitle,
715  $this->message['hist'],
716  [],
717  $query
718  ) )->escaped();
719  return $retVal;
720  }
721 
728  protected function recentChangesBlock() {
729  if ( count( $this->rc_cache ) == 0 ) {
730  return '';
731  }
732 
733  $blockOut = '';
734  foreach ( $this->rc_cache as $block ) {
735  if ( count( $block ) < 2 ) {
736  $blockOut .= $this->recentChangesBlockLine( array_shift( $block ) );
737  } else {
738  $blockOut .= $this->recentChangesBlockGroup( $block );
739  }
740  }
741 
742  return '<div>' . $blockOut . '</div>';
743  }
744 
750  public function endRecentChangesList() {
751  return $this->recentChangesBlock() . '</div>';
752  }
753 }
static newFromID($id, $flags=0)
Create a new Title from an article ID.
Definition: Title.php:417
const RC_CATEGORIZE
Definition: Defines.php:173
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:1418
getLanguage()
Get the Language object.
static linkKnown($target, $html=null, $customAttribs=[], $query=[], $options=[ 'known', 'noclasses'])
Identical to link(), except $options defaults to 'known'.
Definition: Linker.php:264
magic word the default is to use $key to get the and $key value or $key value text $key value html to format the value $key
Definition: hooks.txt:2321
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
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.
Definition: SpecialPage.php:75
static isDeleted($rc, $field)
Determine if said field of a revision is hidden.
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:1798
getTags(RecentChange $rc, array &$classes)
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 just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing 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:1924
$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:1209
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.
the value to return A Title object or null for latest to be modified or replaced by the hook handler or if authentication is not possible after cache objects are set for highlighting & $link
Definition: hooks.txt:2581
Class to simplify the use of log pages.
Definition: LogPage.php:32
$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:248
RCCacheEntryFactory $cacheEntryFactory
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:912
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
static link($target, $html=null, $customAttribs=[], $query=[], $options=[])
This function returns an HTML link to the given target.
Definition: Linker.php:195
const DELETED_TEXT
Definition: Revision.php:76
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:66
$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:2715
insertLogEntry($rc)
Insert a formatted action.
$count
$templateParser
const RC_NEW
Definition: Defines.php:170
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:2338
maybeWatchedLink($link, $watched=false)
const RC_LOG
Definition: Defines.php:171
getOutput()
Get the OutputPage object.