MediaWiki  1.23.15
SpecialContributions.php
Go to the documentation of this file.
1 <?php
30  protected $opts;
31 
32  public function __construct() {
33  parent::__construct( 'Contributions' );
34  }
35 
36  public function execute( $par ) {
37  $this->setHeaders();
38  $this->outputHeader();
39  $out = $this->getOutput();
40  $out->addModuleStyles( 'mediawiki.special' );
41 
42  $this->opts = array();
43  $request = $this->getRequest();
44 
45  if ( $par !== null ) {
46  $target = $par;
47  } else {
48  $target = $request->getVal( 'target' );
49  }
50 
51  // check for radiobox
52  if ( $request->getVal( 'contribs' ) == 'newbie' ) {
53  $target = 'newbies';
54  $this->opts['contribs'] = 'newbie';
55  } elseif ( $par === 'newbies' ) { // b/c for WMF
56  $target = 'newbies';
57  $this->opts['contribs'] = 'newbie';
58  } else {
59  $this->opts['contribs'] = 'user';
60  }
61 
62  $this->opts['deletedOnly'] = $request->getBool( 'deletedOnly' );
63 
64  if ( !strlen( $target ) ) {
65  if ( !$this->including() ) {
66  $out->addHTML( $this->getForm() );
67  }
68 
69  return;
70  }
71 
72  $user = $this->getUser();
73 
74  $this->opts['limit'] = $request->getInt( 'limit', $user->getOption( 'rclimit' ) );
75  $this->opts['target'] = $target;
76  $this->opts['topOnly'] = $request->getBool( 'topOnly' );
77  $this->opts['newOnly'] = $request->getBool( 'newOnly' );
78 
79  $nt = Title::makeTitleSafe( NS_USER, $target );
80  if ( !$nt ) {
81  $out->addHTML( $this->getForm() );
82 
83  return;
84  }
85  $userObj = User::newFromName( $nt->getText(), false );
86  if ( !$userObj ) {
87  $out->addHTML( $this->getForm() );
88 
89  return;
90  }
91  $id = $userObj->getID();
92 
93  if ( $this->opts['contribs'] != 'newbie' ) {
94  $target = $nt->getText();
95  $out->addSubtitle( $this->contributionsSub( $userObj ) );
96  $out->setHTMLTitle( $this->msg(
97  'pagetitle',
98  $this->msg( 'contributions-title', $target )->plain()
99  )->inContentLanguage() );
100  $this->getSkin()->setRelevantUser( $userObj );
101  } else {
102  $out->addSubtitle( $this->msg( 'sp-contributions-newbies-sub' ) );
103  $out->setHTMLTitle( $this->msg(
104  'pagetitle',
105  $this->msg( 'sp-contributions-newbies-title' )->plain()
106  )->inContentLanguage() );
107  }
108 
109  if ( ( $ns = $request->getVal( 'namespace', null ) ) !== null && $ns !== '' ) {
110  $this->opts['namespace'] = intval( $ns );
111  } else {
112  $this->opts['namespace'] = '';
113  }
114 
115  $this->opts['associated'] = $request->getBool( 'associated' );
116  $this->opts['nsInvert'] = (bool)$request->getVal( 'nsInvert' );
117  $this->opts['tagfilter'] = (string)$request->getVal( 'tagfilter' );
118 
119  // Allows reverts to have the bot flag in recent changes. It is just here to
120  // be passed in the form at the top of the page
121  if ( $user->isAllowed( 'markbotedits' ) && $request->getBool( 'bot' ) ) {
122  $this->opts['bot'] = '1';
123  }
124 
125  $skip = $request->getText( 'offset' ) || $request->getText( 'dir' ) == 'prev';
126  # Offset overrides year/month selection
127  if ( $skip ) {
128  $this->opts['year'] = '';
129  $this->opts['month'] = '';
130  } else {
131  $this->opts['year'] = $request->getIntOrNull( 'year' );
132  $this->opts['month'] = $request->getIntOrNull( 'month' );
133  }
134 
135  $feedType = $request->getVal( 'feed' );
136 
137  $feedParams = array(
138  'action' => 'feedcontributions',
139  'user' => $target,
140  );
141  if ( $this->opts['topOnly'] ) {
142  $feedParams['toponly'] = true;
143  }
144  if ( $this->opts['newOnly'] ) {
145  $feedParams['newonly'] = true;
146  }
147  if ( $this->opts['deletedOnly'] ) {
148  $feedParams['deletedonly'] = true;
149  }
150  if ( $this->opts['tagfilter'] !== '' ) {
151  $feedParams['tagfilter'] = $this->opts['tagfilter'];
152  }
153  if ( $this->opts['namespace'] !== '' ) {
154  $feedParams['namespace'] = $this->opts['namespace'];
155  }
156  // Don't use year and month for the feed URL, but pass them on if
157  // we redirect to API (if $feedType is specified)
158  if ( $feedType && $this->opts['year'] !== null ) {
159  $feedParams['year'] = $this->opts['year'];
160  }
161  if ( $feedType && $this->opts['month'] !== null ) {
162  $feedParams['month'] = $this->opts['month'];
163  }
164 
165  if ( $feedType ) {
166  // Maintain some level of backwards compatability
167  // If people request feeds using the old parameters, redirect to API
168  $feedParams['feedformat'] = $feedType;
169  $url = wfAppendQuery( wfScript( 'api' ), $feedParams );
170 
171  $out->redirect( $url, '301' );
172 
173  return;
174  }
175 
176  // Add RSS/atom links
177  $this->addFeedLinks( $feedParams );
178 
179  if ( wfRunHooks( 'SpecialContributionsBeforeMainOutput', array( $id, $userObj, $this ) ) ) {
180  if ( !$this->including() ) {
181  $out->addHTML( $this->getForm() );
182  }
183  $pager = new ContribsPager( $this->getContext(), array(
184  'target' => $target,
185  'contribs' => $this->opts['contribs'],
186  'namespace' => $this->opts['namespace'],
187  'tagfilter' => $this->opts['tagfilter'],
188  'year' => $this->opts['year'],
189  'month' => $this->opts['month'],
190  'deletedOnly' => $this->opts['deletedOnly'],
191  'topOnly' => $this->opts['topOnly'],
192  'newOnly' => $this->opts['newOnly'],
193  'nsInvert' => $this->opts['nsInvert'],
194  'associated' => $this->opts['associated'],
195  ) );
196 
197  if ( !$pager->getNumRows() ) {
198  $out->addWikiMsg( 'nocontribs', $target );
199  } else {
200  # Show a message about slave lag, if applicable
201  $lag = wfGetLB()->safeGetLag( $pager->getDatabase() );
202  if ( $lag > 0 ) {
203  $out->showLagWarning( $lag );
204  }
205 
206  $out->addHTML(
207  '<p>' . $pager->getNavigationBar() . '</p>' .
208  $pager->getBody() .
209  '<p>' . $pager->getNavigationBar() . '</p>'
210  );
211  }
212  $out->preventClickjacking( $pager->getPreventClickjacking() );
213 
214  # Show the appropriate "footer" message - WHOIS tools, etc.
215  if ( $this->opts['contribs'] == 'newbie' ) {
216  $message = 'sp-contributions-footer-newbies';
217  } elseif ( IP::isIPAddress( $target ) ) {
218  $message = 'sp-contributions-footer-anon';
219  } elseif ( $userObj->isAnon() ) {
220  // No message for non-existing users
221  $message = '';
222  } else {
223  $message = 'sp-contributions-footer';
224  }
225 
226  if ( $message ) {
227  if ( !$this->including() ) {
228  if ( !$this->msg( $message, $target )->isDisabled() ) {
229  $out->wrapWikiMsg(
230  "<div class='mw-contributions-footer'>\n$1\n</div>",
231  array( $message, $target ) );
232  }
233  }
234  }
235  }
236  }
237 
245  protected function contributionsSub( $userObj ) {
246  if ( $userObj->isAnon() ) {
247  // Show a warning message that the user being searched for doesn't exists
248  if ( !User::isIP( $userObj ) ) {
249  $this->getOutput()->wrapWikiMsg(
250  "<div class=\"mw-userpage-userdoesnotexist error\">\n\$1\n</div>",
251  array(
252  'contributions-userdoesnotexist',
253  wfEscapeWikiText( $userObj->getName() ),
254  )
255  );
256  }
257  $user = htmlspecialchars( $userObj->getName() );
258  } else {
259  $user = Linker::link( $userObj->getUserPage(), htmlspecialchars( $userObj->getName() ) );
260  }
261  $nt = $userObj->getUserPage();
262  $talk = $userObj->getTalkPage();
263  $links = '';
264  if ( $talk ) {
265  $tools = $this->getUserLinks( $nt, $talk, $userObj );
266  $links = $this->getLanguage()->pipeList( $tools );
267 
268  // Show a note if the user is blocked and display the last block log entry.
269  // Do not expose the autoblocks, since that may lead to a leak of accounts' IPs,
270  // and also this will display a totally irrelevant log entry as a current block.
271  if ( $userObj->isBlocked() && $userObj->getBlock()->getType() != Block::TYPE_AUTO ) {
272  $out = $this->getOutput(); // showLogExtract() wants first parameter by reference
274  $out,
275  'block',
276  $nt,
277  '',
278  array(
279  'lim' => 1,
280  'showIfEmpty' => false,
281  'msgKey' => array(
282  $userObj->isAnon() ?
283  'sp-contributions-blocked-notice-anon' :
284  'sp-contributions-blocked-notice',
285  $userObj->getName() # Support GENDER in 'sp-contributions-blocked-notice'
286  ),
287  'offset' => '' # don't use WebRequest parameter offset
288  )
289  );
290  }
291  }
292 
293  return $this->msg( 'contribsub2' )->rawParams( $user, $links )->params( $userObj->getName() );
294  }
295 
303  public function getUserLinks( Title $userpage, Title $talkpage, User $target ) {
304 
305  $id = $target->getId();
306  $username = $target->getName();
307 
308  $tools[] = Linker::link( $talkpage, $this->msg( 'sp-contributions-talk' )->escaped() );
309 
310  if ( ( $id !== null ) || ( $id === null && IP::isIPAddress( $username ) ) ) {
311  if ( $this->getUser()->isAllowed( 'block' ) ) { # Block / Change block / Unblock links
312  if ( $target->isBlocked() && $target->getBlock()->getType() != Block::TYPE_AUTO ) {
313  $tools[] = Linker::linkKnown( # Change block link
314  SpecialPage::getTitleFor( 'Block', $username ),
315  $this->msg( 'change-blocklink' )->escaped()
316  );
317  $tools[] = Linker::linkKnown( # Unblock link
318  SpecialPage::getTitleFor( 'Unblock', $username ),
319  $this->msg( 'unblocklink' )->escaped()
320  );
321  } else { # User is not blocked
322  $tools[] = Linker::linkKnown( # Block link
323  SpecialPage::getTitleFor( 'Block', $username ),
324  $this->msg( 'blocklink' )->escaped()
325  );
326  }
327  }
328 
329  # Block log link
330  $tools[] = Linker::linkKnown(
331  SpecialPage::getTitleFor( 'Log', 'block' ),
332  $this->msg( 'sp-contributions-blocklog' )->escaped(),
333  array(),
334  array( 'page' => $userpage->getPrefixedText() )
335  );
336 
337  # Suppression log link (bug 59120)
338  if ( $this->getUser()->isAllowed( 'suppressionlog' ) ) {
339  $tools[] = Linker::linkKnown(
340  SpecialPage::getTitleFor( 'Log', 'suppress' ),
341  $this->msg( 'sp-contributions-suppresslog' )->escaped(),
342  array(),
343  array( 'offender' => $username )
344  );
345  }
346  }
347  # Uploads
348  $tools[] = Linker::linkKnown(
349  SpecialPage::getTitleFor( 'Listfiles', $username ),
350  $this->msg( 'sp-contributions-uploads' )->escaped()
351  );
352 
353  # Other logs link
354  $tools[] = Linker::linkKnown(
355  SpecialPage::getTitleFor( 'Log', $username ),
356  $this->msg( 'sp-contributions-logs' )->escaped()
357  );
358 
359  # Add link to deleted user contributions for priviledged users
360  if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) {
361  $tools[] = Linker::linkKnown(
362  SpecialPage::getTitleFor( 'DeletedContributions', $username ),
363  $this->msg( 'sp-contributions-deleted' )->escaped()
364  );
365  }
366 
367  # Add a link to change user rights for privileged users
368  $userrightsPage = new UserrightsPage();
369  $userrightsPage->setContext( $this->getContext() );
370  if ( $userrightsPage->userCanChangeRights( $target ) ) {
371  $tools[] = Linker::linkKnown(
372  SpecialPage::getTitleFor( 'Userrights', $username ),
373  $this->msg( 'sp-contributions-userrights' )->escaped()
374  );
375  }
376 
377  wfRunHooks( 'ContributionsToolLinks', array( $id, $userpage, &$tools ) );
378 
379  return $tools;
380  }
381 
386  protected function getForm() {
387  global $wgScript;
388 
389  $this->opts['title'] = $this->getPageTitle()->getPrefixedText();
390  if ( !isset( $this->opts['target'] ) ) {
391  $this->opts['target'] = '';
392  } else {
393  $this->opts['target'] = str_replace( '_', ' ', $this->opts['target'] );
394  }
395 
396  if ( !isset( $this->opts['namespace'] ) ) {
397  $this->opts['namespace'] = '';
398  }
399 
400  if ( !isset( $this->opts['nsInvert'] ) ) {
401  $this->opts['nsInvert'] = '';
402  }
403 
404  if ( !isset( $this->opts['associated'] ) ) {
405  $this->opts['associated'] = false;
406  }
407 
408  if ( !isset( $this->opts['contribs'] ) ) {
409  $this->opts['contribs'] = 'user';
410  }
411 
412  if ( !isset( $this->opts['year'] ) ) {
413  $this->opts['year'] = '';
414  }
415 
416  if ( !isset( $this->opts['month'] ) ) {
417  $this->opts['month'] = '';
418  }
419 
420  if ( $this->opts['contribs'] == 'newbie' ) {
421  $this->opts['target'] = '';
422  }
423 
424  if ( !isset( $this->opts['tagfilter'] ) ) {
425  $this->opts['tagfilter'] = '';
426  }
427 
428  if ( !isset( $this->opts['topOnly'] ) ) {
429  $this->opts['topOnly'] = false;
430  }
431 
432  if ( !isset( $this->opts['newOnly'] ) ) {
433  $this->opts['newOnly'] = false;
434  }
435 
436  $form = Html::openElement(
437  'form',
438  array(
439  'method' => 'get',
440  'action' => $wgScript,
441  'class' => 'mw-contributions-form'
442  )
443  );
444 
445  # Add hidden params for tracking except for parameters in $skipParameters
446  $skipParameters = array(
447  'namespace',
448  'nsInvert',
449  'deletedOnly',
450  'target',
451  'contribs',
452  'year',
453  'month',
454  'topOnly',
455  'newOnly',
456  'associated'
457  );
458 
459  foreach ( $this->opts as $name => $value ) {
460  if ( in_array( $name, $skipParameters ) ) {
461  continue;
462  }
463  $form .= "\t" . Html::hidden( $name, $value ) . "\n";
464  }
465 
466  $tagFilter = ChangeTags::buildTagFilterSelector( $this->opts['tagfilter'] );
467 
468  if ( $tagFilter ) {
469  $filterSelection = Html::rawElement(
470  'td',
471  array( 'class' => 'mw-label' ),
472  array_shift( $tagFilter )
473  );
474  $filterSelection .= Html::rawElement(
475  'td',
476  array( 'class' => 'mw-input' ),
477  implode( '&#160', $tagFilter )
478  );
479  } else {
480  $filterSelection = Html::rawElement( 'td', array( 'colspan' => 2 ), '' );
481  }
482 
483  $labelNewbies = Xml::radioLabel(
484  $this->msg( 'sp-contributions-newbies' )->text(),
485  'contribs',
486  'newbie',
487  'newbie',
488  $this->opts['contribs'] == 'newbie',
489  array( 'class' => 'mw-input' )
490  );
491  $labelUsername = Xml::radioLabel(
492  $this->msg( 'sp-contributions-username' )->text(),
493  'contribs',
494  'user',
495  'user',
496  $this->opts['contribs'] == 'user',
497  array( 'class' => 'mw-input' )
498  );
499  $input = Html::input(
500  'target',
501  $this->opts['target'],
502  'text',
503  array( 'size' => '40', 'required' => '', 'class' => 'mw-input' ) +
504  ( $this->opts['target'] ? array() : array( 'autofocus' )
505  )
506  );
507  $targetSelection = Html::rawElement(
508  'td',
509  array( 'colspan' => 2 ),
510  $labelNewbies . '<br />' . $labelUsername . ' ' . $input . ' '
511  );
512 
513  $namespaceSelection = Xml::tags(
514  'td',
515  array( 'class' => 'mw-label' ),
516  Xml::label(
517  $this->msg( 'namespace' )->text(),
518  'namespace',
519  ''
520  )
521  );
522  $namespaceSelection .= Html::rawElement(
523  'td',
524  null,
525  Html::namespaceSelector(
526  array( 'selected' => $this->opts['namespace'], 'all' => '' ),
527  array(
528  'name' => 'namespace',
529  'id' => 'namespace',
530  'class' => 'namespaceselector',
531  )
532  ) . '&#160;' .
533  Html::rawElement(
534  'span',
535  array( 'style' => 'white-space: nowrap' ),
536  Xml::checkLabel(
537  $this->msg( 'invert' )->text(),
538  'nsInvert',
539  'nsInvert',
540  $this->opts['nsInvert'],
541  array(
542  'title' => $this->msg( 'tooltip-invert' )->text(),
543  'class' => 'mw-input'
544  )
545  ) . '&#160;'
546  ) .
547  Html::rawElement( 'span', array( 'style' => 'white-space: nowrap' ),
548  Xml::checkLabel(
549  $this->msg( 'namespace_association' )->text(),
550  'associated',
551  'associated',
552  $this->opts['associated'],
553  array(
554  'title' => $this->msg( 'tooltip-namespace_association' )->text(),
555  'class' => 'mw-input'
556  )
557  ) . '&#160;'
558  )
559  );
560 
561  if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) {
562  $deletedOnlyCheck = Html::rawElement(
563  'span',
564  array( 'style' => 'white-space: nowrap' ),
565  Xml::checkLabel(
566  $this->msg( 'history-show-deleted' )->text(),
567  'deletedOnly',
568  'mw-show-deleted-only',
569  $this->opts['deletedOnly'],
570  array( 'class' => 'mw-input' )
571  )
572  );
573  } else {
574  $deletedOnlyCheck = '';
575  }
576 
577  $checkLabelTopOnly = Html::rawElement(
578  'span',
579  array( 'style' => 'white-space: nowrap' ),
580  Xml::checkLabel(
581  $this->msg( 'sp-contributions-toponly' )->text(),
582  'topOnly',
583  'mw-show-top-only',
584  $this->opts['topOnly'],
585  array( 'class' => 'mw-input' )
586  )
587  );
588  $checkLabelNewOnly = Html::rawElement(
589  'span',
590  array( 'style' => 'white-space: nowrap' ),
591  Xml::checkLabel(
592  $this->msg( 'sp-contributions-newonly' )->text(),
593  'newOnly',
594  'mw-show-new-only',
595  $this->opts['newOnly'],
596  array( 'class' => 'mw-input' )
597  )
598  );
599  $extraOptions = Html::rawElement(
600  'td',
601  array( 'colspan' => 2 ),
602  $deletedOnlyCheck . $checkLabelTopOnly . $checkLabelNewOnly
603  );
604 
605  $dateSelectionAndSubmit = Xml::tags( 'td', array( 'colspan' => 2 ),
606  Xml::dateMenu(
607  $this->opts['year'] === '' ? MWTimestamp::getInstance()->format( 'Y' ) : $this->opts['year'],
608  $this->opts['month']
609  ) . ' ' .
610  Xml::submitButton(
611  $this->msg( 'sp-contributions-submit' )->text(),
612  array( 'class' => 'mw-submit' )
613  )
614  );
615 
616  $form .= Xml::fieldset( $this->msg( 'sp-contributions-search' )->text() );
617  $form .= Html::rawElement( 'table', array( 'class' => 'mw-contributions-table' ), "\n" .
618  Html::rawElement( 'tr', array(), $targetSelection ) . "\n" .
619  Html::rawElement( 'tr', array(), $namespaceSelection ) . "\n" .
620  Html::rawElement( 'tr', array(), $filterSelection ) . "\n" .
621  Html::rawElement( 'tr', array(), $extraOptions ) . "\n" .
622  Html::rawElement( 'tr', array(), $dateSelectionAndSubmit ) . "\n"
623  );
624 
625  $explain = $this->msg( 'sp-contributions-explain' );
626  if ( !$explain->isBlank() ) {
627  $form .= "<p id='mw-sp-contributions-explain'>{$explain->parse()}</p>";
628  }
629 
630  $form .= Xml::closeElement( 'fieldset' ) . Xml::closeElement( 'form' );
631 
632  return $form;
633  }
634 
635  protected function getGroupName() {
636  return 'users';
637  }
638 }
639 
644 class ContribsPager extends ReverseChronologicalPager {
645  public $mDefaultDirection = true;
646  public $messages;
647  public $target;
648  public $namespace = '';
649  public $mDb;
650  public $preventClickjacking = false;
651 
653  public $mDbSecondary;
654 
658  protected $mParentLens;
659 
660  function __construct( IContextSource $context, array $options ) {
661  parent::__construct( $context );
662 
663  $msgs = array(
664  'diff',
665  'hist',
666  'newarticle',
667  'pipe-separator',
668  'rev-delundel',
669  'rollbacklink',
670  'uctop'
671  );
672 
673  foreach ( $msgs as $msg ) {
674  $this->messages[$msg] = $this->msg( $msg )->escaped();
675  }
676 
677  $this->target = isset( $options['target'] ) ? $options['target'] : '';
678  $this->contribs = isset( $options['contribs'] ) ? $options['contribs'] : 'users';
679  $this->namespace = isset( $options['namespace'] ) ? $options['namespace'] : '';
680  $this->tagFilter = isset( $options['tagfilter'] ) ? $options['tagfilter'] : false;
681  $this->nsInvert = isset( $options['nsInvert'] ) ? $options['nsInvert'] : false;
682  $this->associated = isset( $options['associated'] ) ? $options['associated'] : false;
683 
684  $this->deletedOnly = !empty( $options['deletedOnly'] );
685  $this->topOnly = !empty( $options['topOnly'] );
686  $this->newOnly = !empty( $options['newOnly'] );
687 
688  $year = isset( $options['year'] ) ? $options['year'] : false;
689  $month = isset( $options['month'] ) ? $options['month'] : false;
690  $this->getDateCond( $year, $month );
691 
692  // Most of this code will use the 'contributions' group DB, which can map to slaves
693  // with extra user based indexes or partioning by user. The additional metadata
694  // queries should use a regular slave since the lookup pattern is not all by user.
695  $this->mDbSecondary = wfGetDB( DB_SLAVE ); // any random slave
696  $this->mDb = wfGetDB( DB_SLAVE, 'contributions' );
697  }
698 
699  function getDefaultQuery() {
700  $query = parent::getDefaultQuery();
701  $query['target'] = $this->target;
702 
703  return $query;
704  }
705 
715  function reallyDoQuery( $offset, $limit, $descending ) {
716  list( $tables, $fields, $conds, $fname, $options, $join_conds ) = $this->buildQueryInfo(
717  $offset,
718  $limit,
719  $descending
720  );
721  $pager = $this;
722 
723  /*
724  * This hook will allow extensions to add in additional queries, so they can get their data
725  * in My Contributions as well. Extensions should append their results to the $data array.
726  *
727  * Extension queries have to implement the navbar requirement as well. They should
728  * - have a column aliased as $pager->getIndexField()
729  * - have LIMIT set
730  * - have a WHERE-clause that compares the $pager->getIndexField()-equivalent column to the offset
731  * - have the ORDER BY specified based upon the details provided by the navbar
732  *
733  * See includes/Pager.php buildQueryInfo() method on how to build LIMIT, WHERE & ORDER BY
734  *
735  * &$data: an array of results of all contribs queries
736  * $pager: the ContribsPager object hooked into
737  * $offset: see phpdoc above
738  * $limit: see phpdoc above
739  * $descending: see phpdoc above
740  */
741  $data = array( $this->mDb->select(
742  $tables, $fields, $conds, $fname, $options, $join_conds
743  ) );
744  wfRunHooks(
746  array( &$data, $pager, $offset, $limit, $descending )
747  );
748 
749  $result = array();
750 
751  // loop all results and collect them in an array
752  foreach ( $data as $query ) {
753  foreach ( $query as $i => $row ) {
754  // use index column as key, allowing us to easily sort in PHP
755  $result[$row->{$this->getIndexField()} . "-$i"] = $row;
756  }
757  }
758 
759  // sort results
760  if ( $descending ) {
761  ksort( $result );
762  } else {
763  krsort( $result );
764  }
765 
766  // enforce limit
767  $result = array_slice( $result, 0, $limit );
768 
769  // get rid of array keys
770  $result = array_values( $result );
771 
772  return new FakeResultWrapper( $result );
773  }
774 
775  function getQueryInfo() {
776  list( $tables, $index, $userCond, $join_cond ) = $this->getUserCond();
777 
778  $user = $this->getUser();
779  $conds = array_merge( $userCond, $this->getNamespaceCond() );
780 
781  // Paranoia: avoid brute force searches (bug 17342)
782  if ( !$user->isAllowed( 'deletedhistory' ) ) {
783  $conds[] = $this->mDb->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0';
784  } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
785  $conds[] = $this->mDb->bitAnd( 'rev_deleted', Revision::SUPPRESSED_USER ) .
786  ' != ' . Revision::SUPPRESSED_USER;
787  }
788 
789  # Don't include orphaned revisions
790  $join_cond['page'] = Revision::pageJoinCond();
791  # Get the current user name for accounts
792  $join_cond['user'] = Revision::userJoinCond();
793 
794  $options = array();
795  if ( $index ) {
796  $options['USE INDEX'] = array( 'revision' => $index );
797  }
798 
799  $queryInfo = array(
800  'tables' => $tables,
801  'fields' => array_merge(
804  array( 'page_namespace', 'page_title', 'page_is_new',
805  'page_latest', 'page_is_redirect', 'page_len' )
806  ),
807  'conds' => $conds,
808  'options' => $options,
809  'join_conds' => $join_cond
810  );
811 
813  $queryInfo['tables'],
814  $queryInfo['fields'],
815  $queryInfo['conds'],
816  $queryInfo['join_conds'],
817  $queryInfo['options'],
818  $this->tagFilter
819  );
820 
821  wfRunHooks( 'ContribsPager::getQueryInfo', array( &$this, &$queryInfo ) );
822 
823  return $queryInfo;
824  }
825 
826  function getUserCond() {
827  $condition = array();
828  $join_conds = array();
829  $tables = array( 'revision', 'page', 'user' );
830  $index = false;
831  if ( $this->contribs == 'newbie' ) {
832  $max = $this->mDb->selectField( 'user', 'max(user_id)', false, __METHOD__ );
833  $condition[] = 'rev_user >' . (int)( $max - $max / 100 );
834  # ignore local groups with the bot right
835  # @todo FIXME: Global groups may have 'bot' rights
836  $groupsWithBotPermission = User::getGroupsWithPermission( 'bot' );
837  if ( count( $groupsWithBotPermission ) ) {
838  $tables[] = 'user_groups';
839  $condition[] = 'ug_group IS NULL';
840  $join_conds['user_groups'] = array(
841  'LEFT JOIN', array(
842  'ug_user = rev_user',
843  'ug_group' => $groupsWithBotPermission
844  )
845  );
846  }
847  } else {
848  $uid = User::idFromName( $this->target );
849  if ( $uid ) {
850  $condition['rev_user'] = $uid;
851  $index = 'user_timestamp';
852  } else {
853  $condition['rev_user_text'] = $this->target;
854  $index = 'usertext_timestamp';
855  }
856  }
857 
858  if ( $this->deletedOnly ) {
859  $condition[] = 'rev_deleted != 0';
860  }
861 
862  if ( $this->topOnly ) {
863  $condition[] = 'rev_id = page_latest';
864  }
865 
866  if ( $this->newOnly ) {
867  $condition[] = 'rev_parent_id = 0';
868  }
869 
870  return array( $tables, $index, $condition, $join_conds );
871  }
872 
873  function getNamespaceCond() {
874  if ( $this->namespace !== '' ) {
875  $selectedNS = $this->mDb->addQuotes( $this->namespace );
876  $eq_op = $this->nsInvert ? '!=' : '=';
877  $bool_op = $this->nsInvert ? 'AND' : 'OR';
878 
879  if ( !$this->associated ) {
880  return array( "page_namespace $eq_op $selectedNS" );
881  }
882 
883  $associatedNS = $this->mDb->addQuotes(
884  MWNamespace::getAssociated( $this->namespace )
885  );
886 
887  return array(
888  "page_namespace $eq_op $selectedNS " .
889  $bool_op .
890  " page_namespace $eq_op $associatedNS"
891  );
892  }
893 
894  return array();
895  }
896 
897  function getIndexField() {
898  return 'rev_timestamp';
899  }
900 
901  function doBatchLookups() {
902  # Do a link batch query
903  $this->mResult->seek( 0 );
904  $revIds = array();
905  $batch = new LinkBatch();
906  # Give some pointers to make (last) links
907  foreach ( $this->mResult as $row ) {
908  if ( isset( $row->rev_parent_id ) && $row->rev_parent_id ) {
909  $revIds[] = $row->rev_parent_id;
910  }
911  if ( isset( $row->rev_id ) ) {
912  if ( $this->contribs === 'newbie' ) { // multiple users
913  $batch->add( NS_USER, $row->user_name );
914  $batch->add( NS_USER_TALK, $row->user_name );
915  }
916  $batch->add( $row->page_namespace, $row->page_title );
917  }
918  }
919  $this->mParentLens = Revision::getParentLengths( $this->mDbSecondary, $revIds );
920  $batch->execute();
921  $this->mResult->seek( 0 );
922  }
923 
927  function getStartBody() {
928  return "<ul>\n";
929  }
930 
934  function getEndBody() {
935  return "</ul>\n";
936  }
937 
950  function formatRow( $row ) {
951  wfProfileIn( __METHOD__ );
952 
953  $ret = '';
954  $classes = array();
955 
956  /*
957  * There may be more than just revision rows. To make sure that we'll only be processing
958  * revisions here, let's _try_ to build a revision out of our row (without displaying
959  * notices though) and then trying to grab data from the built object. If we succeed,
960  * we're definitely dealing with revision data and we may proceed, if not, we'll leave it
961  * to extensions to subscribe to the hook to parse the row.
962  */
964  try {
965  $rev = new Revision( $row );
966  $validRevision = (bool)$rev->getId();
967  } catch ( MWException $e ) {
968  $validRevision = false;
969  }
971 
972  if ( $validRevision ) {
973  $classes = array();
974 
975  $page = Title::newFromRow( $row );
977  $page,
978  htmlspecialchars( $page->getPrefixedText() ),
979  array( 'class' => 'mw-contributions-title' ),
980  $page->isRedirect() ? array( 'redirect' => 'no' ) : array()
981  );
982  # Mark current revisions
983  $topmarktext = '';
984  $user = $this->getUser();
985  if ( $row->rev_id == $row->page_latest ) {
986  $topmarktext .= '<span class="mw-uctop">' . $this->messages['uctop'] . '</span>';
987  # Add rollback link
988  if ( !$row->page_is_new && $page->quickUserCan( 'rollback', $user )
989  && $page->quickUserCan( 'edit', $user )
990  ) {
991  $this->preventClickjacking();
992  $topmarktext .= ' ' . Linker::generateRollback( $rev, $this->getContext() );
993  }
994  }
995  # Is there a visible previous revision?
996  if ( $rev->userCan( Revision::DELETED_TEXT, $user ) && $rev->getParentId() !== 0 ) {
997  $difftext = Linker::linkKnown(
998  $page,
999  $this->messages['diff'],
1000  array(),
1001  array(
1002  'diff' => 'prev',
1003  'oldid' => $row->rev_id
1004  )
1005  );
1006  } else {
1007  $difftext = $this->messages['diff'];
1008  }
1009  $histlink = Linker::linkKnown(
1010  $page,
1011  $this->messages['hist'],
1012  array(),
1013  array( 'action' => 'history' )
1014  );
1015 
1016  if ( $row->rev_parent_id === null ) {
1017  // For some reason rev_parent_id isn't populated for this row.
1018  // Its rumoured this is true on wikipedia for some revisions (bug 34922).
1019  // Next best thing is to have the total number of bytes.
1020  $chardiff = ' <span class="mw-changeslist-separator">. .</span> ';
1021  $chardiff .= Linker::formatRevisionSize( $row->rev_len );
1022  $chardiff .= ' <span class="mw-changeslist-separator">. .</span> ';
1023  } else {
1024  $parentLen = 0;
1025  if ( isset( $this->mParentLens[$row->rev_parent_id] ) ) {
1026  $parentLen = $this->mParentLens[$row->rev_parent_id];
1027  }
1028 
1029  $chardiff = ' <span class="mw-changeslist-separator">. .</span> ';
1031  $parentLen,
1032  $row->rev_len,
1033  $this->getContext()
1034  );
1035  $chardiff .= ' <span class="mw-changeslist-separator">. .</span> ';
1036  }
1037 
1038  $lang = $this->getLanguage();
1039  $comment = $lang->getDirMark() . Linker::revComment( $rev, false, true );
1040  $date = $lang->userTimeAndDate( $row->rev_timestamp, $user );
1041  if ( $rev->userCan( Revision::DELETED_TEXT, $user ) ) {
1042  $d = Linker::linkKnown(
1043  $page,
1044  htmlspecialchars( $date ),
1045  array( 'class' => 'mw-changeslist-date' ),
1046  array( 'oldid' => intval( $row->rev_id ) )
1047  );
1048  } else {
1049  $d = htmlspecialchars( $date );
1050  }
1051  if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
1052  $d = '<span class="history-deleted">' . $d . '</span>';
1053  }
1054 
1055  # Show user names for /newbies as there may be different users.
1056  # Note that we already excluded rows with hidden user names.
1057  if ( $this->contribs == 'newbie' ) {
1058  $userlink = ' . . ' . $lang->getDirMark() . Linker::userLink( $rev->getUser(), $rev->getUserText() );
1059  $userlink .= ' ' . $this->msg( 'parentheses' )->rawParams(
1060  Linker::userTalkLink( $rev->getUser(), $rev->getUserText() ) )->escaped() . ' ';
1061  } else {
1062  $userlink = '';
1063  }
1064 
1065  if ( $rev->getParentId() === 0 ) {
1066  $nflag = ChangesList::flag( 'newpage' );
1067  } else {
1068  $nflag = '';
1069  }
1070 
1071  if ( $rev->isMinor() ) {
1072  $mflag = ChangesList::flag( 'minor' );
1073  } else {
1074  $mflag = '';
1075  }
1076 
1077  $del = Linker::getRevDeleteLink( $user, $rev, $page );
1078  if ( $del !== '' ) {
1079  $del .= ' ';
1080  }
1081 
1082  $diffHistLinks = $this->msg( 'parentheses' )
1083  ->rawParams( $difftext . $this->messages['pipe-separator'] . $histlink )
1084  ->escaped();
1085  $ret = "{$del}{$d} {$diffHistLinks}{$chardiff}{$nflag}{$mflag} ";
1086  $ret .= "{$link}{$userlink} {$comment} {$topmarktext}";
1087 
1088  # Denote if username is redacted for this edit
1089  if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
1090  $ret .= " <strong>" .
1091  $this->msg( 'rev-deleted-user-contribs' )->escaped() .
1092  "</strong>";
1093  }
1094 
1095  # Tags, if any.
1096  list( $tagSummary, $newClasses ) = ChangeTags::formatSummaryRow(
1097  $row->ts_tags,
1098  'contributions'
1099  );
1100  $classes = array_merge( $classes, $newClasses );
1101  $ret .= " $tagSummary";
1102  }
1103 
1104  // Let extensions add data
1105  wfRunHooks( 'ContributionsLineEnding', array( $this, &$ret, $row, &$classes ) );
1106 
1107  if ( $classes === array() && $ret === '' ) {
1108  wfDebug( "Dropping Special:Contribution row that could not be formatted\n" );
1109  $ret = "<!-- Could not format Special:Contribution row. -->\n";
1110  } else {
1111  $ret = Html::rawElement( 'li', array( 'class' => $classes ), $ret ) . "\n";
1112  }
1113 
1114  wfProfileOut( __METHOD__ );
1115 
1116  return $ret;
1117  }
1118 
1123  function getSqlComment() {
1124  if ( $this->namespace || $this->deletedOnly ) {
1125  // potentially slow, see CR r58153
1126  return 'contributions page filtered for namespace or RevisionDeleted edits';
1127  } else {
1128  return 'contributions page unfiltered';
1129  }
1130  }
1131 
1132  protected function preventClickjacking() {
1133  $this->preventClickjacking = true;
1134  }
1135 
1139  public function getPreventClickjacking() {
1140  return $this->preventClickjacking;
1141  }
1142 }
Revision\DELETED_USER
const DELETED_USER
Definition: Revision.php:67
Linker\generateRollback
static generateRollback( $rev, IContextSource $context=null, $options=array( 'verify'))
Generate a rollback link for a given revision.
Definition: Linker.php:1779
$request
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 my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled also a ContextSource error or success you ll probably need to make sure the header is varied on WebRequest $request
Definition: hooks.txt:1961
Linker\userTalkLink
static userTalkLink( $userId, $userText)
Definition: Linker.php:1173
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
Revision\pageJoinCond
static pageJoinCond()
Return the value of a select() page conds array for the page table.
Definition: Revision.php:396
LinkBatch
Class representing a list of titles The execute() method checks them all for existence and adds them ...
Definition: LinkBatch.php:30
$tables
namespace and then decline to actually register it RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist & $tables
Definition: hooks.txt:815
Linker\userLink
static userLink( $userId, $userName, $altUserName=false)
Make user link (or user contributions for unregistered users)
Definition: Linker.php:1081
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:535
ContribsPager\getUserCond
getUserCond()
Definition: SpecialContributions.php:824
SpecialContributions\getForm
getForm()
Generates the namespace selector form with hidden attributes.
Definition: SpecialContributions.php:386
ContribsPager\reallyDoQuery
reallyDoQuery( $offset, $limit, $descending)
This method basically executes the exact same code as the parent class, though with a hook added,...
Definition: SpecialContributions.php:713
wfGetLB
wfGetLB( $wiki=false)
Get a load balancer object.
Definition: GlobalFunctions.php:3724
text
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
Definition: design.txt:12
wfProfileIn
wfProfileIn( $functionname)
Begin profiling of a function.
Definition: Profiler.php:33
$ret
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:1530
wfSuppressWarnings
wfSuppressWarnings( $end=false)
Reference-counted warning suppression.
Definition: GlobalFunctions.php:2434
ContribsPager\getSqlComment
getSqlComment()
Overwrite Pager function and return a helpful comment.
Definition: SpecialContributions.php:1121
ContribsPager\formatRow
formatRow( $row)
Generates each row in the contributions list.
Definition: SpecialContributions.php:948
User\newFromName
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:389
SpecialPage\getSkin
getSkin()
Shortcut to get the skin being used for this instance.
Definition: SpecialPage.php:555
IncludableSpecialPage
Shortcut to construct an includable special page.
Definition: IncludableSpecialPage.php:29
SpecialPage\getLanguage
getLanguage()
Shortcut to get user's language.
Definition: SpecialPage.php:578
messages
namespace and then decline to actually register it RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist but no entry for that model exists in $wgContentHandlers if desired whether it is OK to use $contentModel on $title Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok in case the handler function wants to provide a converted Content object Note that $result getContentModel() must return $toModel. Handler functions that modify $result should generally return false to further attempts at conversion. 'ContribsPager you ll need to handle error messages
Definition: hooks.txt:896
$link
set to $title object and return false for a match for latest after cache objects are set use the ContentHandler facility to handle CSS and JavaScript for highlighting & $link
Definition: hooks.txt:2160
ContribsPager\doBatchLookups
doBatchLookups()
Called from getBody(), before getStartBody() is called and after doQuery() was called.
Definition: SpecialContributions.php:899
Linker\linkKnown
static linkKnown( $target, $html=null, $customAttribs=array(), $query=array(), $options=array( 'known', 'noclasses'))
Identical to link(), except $options defaults to 'known'.
Definition: Linker.php:264
ChangesList\flag
static flag( $flag)
Provide the "<abbr>" element appropriate to a given abbreviated flag, namely the flag indicating a ne...
Definition: ChangesList.php:132
Linker\link
static link( $target, $html=null, $customAttribs=array(), $query=array(), $options=array())
This function returns an HTML link to the given target.
Definition: Linker.php:192
wfAppendQuery
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
Definition: GlobalFunctions.php:506
Revision
Definition: Revision.php:26
ContribsPager\getPreventClickjacking
getPreventClickjacking()
Definition: SpecialContributions.php:1137
title
to move a page</td >< td > &*You are moving the page across *A non empty talk page already exists under the new or *You uncheck the box below In those you will have to move or merge the page manually if desired</td >< td > be sure to &You are responsible for making sure that links continue to point where they are supposed to go Note that the page will &a page at the new title
Definition: All_system_messages.txt:2703
SpecialContributions\execute
execute( $par)
Default execute method Checks user permissions, calls the function given in mFunction.
Definition: SpecialContributions.php:36
ContribsPager\getNamespaceCond
getNamespaceCond()
Definition: SpecialContributions.php:871
MWException
MediaWiki exception.
Definition: MWException.php:26
$out
$out
Definition: UtfNormalGenerate.php:167
SpecialPage\addFeedLinks
addFeedLinks( $params)
Adds RSS/atom links.
Definition: SpecialPage.php:630
ChangeTags\modifyDisplayQuery
static modifyDisplayQuery(&$tables, &$fields, &$conds, &$join_conds, &$options, $filter_tag=false)
Applies all tags-related changes to a query.
Definition: ChangeTags.php:202
wfRestoreWarnings
wfRestoreWarnings()
Restore error level to previous value.
Definition: GlobalFunctions.php:2464
wfScript
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
Definition: GlobalFunctions.php:3794
table
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global then executing the whole list after the page is displayed We don t do anything smart like collating updates to the same table or such because the list is almost always going to have just one item on if so it s not worth the trouble Since there is a job queue in the jobs table
Definition: deferred.txt:11
ContribsPager\getStartBody
getStartBody()
Definition: SpecialContributions.php:925
Title\newFromRow
static newFromRow( $row)
Make a Title object from a DB row.
Definition: Title.php:345
wfProfileOut
wfProfileOut( $functionname='missing')
Stop profiling of a function.
Definition: Profiler.php:46
wfRunHooks
wfRunHooks( $event, array $args=array(), $deprecatedVersion=null)
Call hook functions defined in $wgHooks.
Definition: GlobalFunctions.php:4066
User\isIP
static isIP( $name)
Does the string match an anonymous IPv4 address?
Definition: User.php:555
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
SpecialPage\setHeaders
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
Definition: SpecialPage.php:352
SpecialPage\getUser
getUser()
Shortcut to get the User executing this instance.
Definition: SpecialPage.php:545
form
null means default in associative array form
Definition: hooks.txt:1530
$comment
$comment
Definition: importImages.php:107
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:188
SpecialPage\getContext
getContext()
Gets the context this SpecialPage is executed in.
Definition: SpecialPage.php:508
$options
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 & $options
Definition: hooks.txt:1530
ContribsPager
Pager for Special:Contributions.
Definition: SpecialContributions.php:644
wfDebug
wfDebug( $text, $dest='all')
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:980
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:422
Linker\revComment
static revComment(Revision $rev, $local=false, $isPublic=false)
Wrap and format the given revision's comment block, if the current user is allowed to view it.
Definition: Linker.php:1587
NS_USER_TALK
const NS_USER_TALK
Definition: Defines.php:82
user
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 and we might be restricted by PHP settings such as safe mode or open_basedir We cannot assume that the software even has read access anywhere useful Many shared hosts run all users web applications under the same user
Definition: distributors.txt:9
action
action
Definition: parserTests.txt:378
SpecialPage\msg
msg()
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:609
Revision\getParentLengths
static getParentLengths( $db, array $revIds)
Do a batched query to get the parent revision lengths.
Definition: Revision.php:503
Linker\getRevDeleteLink
static getRevDeleteLink(User $user, Revision $rev, Title $title)
Get a revision-deletion link, or disabled link, or nothing, depending on user permissions & the setti...
Definition: Linker.php:2164
$tools
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title after the basic globals have been set but before ordinary actions take place change it to the message you want to define which works for all SkinTemplate type skins $tools
Definition: hooks.txt:1684
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:525
Linker\formatRevisionSize
static formatRevisionSize( $size)
Definition: Linker.php:1609
ChangesList\showCharacterDifference
static showCharacterDifference( $old, $new, IContextSource $context=null)
Show formatted char difference.
Definition: ChangesList.php:189
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:2124
SpecialContributions\$opts
$opts
Definition: SpecialContributions.php:30
Block\TYPE_AUTO
const TYPE_AUTO
Definition: Block.php:50
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:237
SpecialContributions\getUserLinks
getUserLinks(Title $userpage, Title $talkpage, User $target)
Links to different places.
Definition: SpecialContributions.php:303
only
published in in Madrid In the first edition of the Vocabolario for was published In in Rotterdam was the Dictionnaire Universel ! html< p > The first monolingual dictionary written in a Romance language was< i > Sebastián Covarrubias</i >< i > Tesoro de la lengua castellana o published in in Madrid In the first edition of the< i > Vocabolario dell< a href="/index.php?title=Accademia_della_Crusca&amp;action=edit&amp;redlink=1" class="new" title="Accademia della Crusca (page does not exist)"> Accademia della Crusca</a ></i > for was published In in Rotterdam was the< i > Dictionnaire Universel</i ></p > ! end ! test Italics and ! wikitext foo ! html< p >< i > foo</i ></p > !end ! test Italics and ! wikitext foo ! html< p >< i > foo</i ></p > !end ! test Italics and ! wikitext foo ! html< p >< i > foo</i ></p > !end ! test Italics and ! wikitext foo ! html php< p >< i > foo</i ></p > ! html parsoid< p >< i > foo</i >< b ></b ></p > !end ! test Italics and ! wikitext foo ! html< p >< i > foo</i ></p > !end ! test Italics and ! wikitext foo ! html< p >< b > foo</b ></p > !end ! test Italics and ! wikitext foo ! html< p >< b > foo</b ></p > !end ! test Italics and ! wikitext foo ! html php< p >< b > foo</b ></p > ! html parsoid< p >< b > foo</b >< i ></i ></p > !end ! test Italics and ! wikitext foo ! html< p >< i > foo</i ></p > !end ! test Italics and ! wikitext foo ! html< p >< b > foo</b ></p > !end ! test Italics and ! wikitext foo ! html< p >< b > foo</b ></p > !end ! test Italics and ! wikitext foo ! html php< p >< b > foo</b ></p > ! html parsoid< p >< b > foo</b >< i ></i ></p > !end ! test Italics and ! options ! wikitext foo ! html< p >< b >< i > foo</i ></b ></p > !end ! test Italics and ! wikitext foo ! html< p >< i >< b > foo</b ></i ></p > !end ! test Italics and ! wikitext foo ! html< p >< i >< b > foo</b ></i ></p > !end ! test Italics and ! wikitext foo ! html< p >< i >< b > foo</b ></i ></p > !end ! test Italics and ! wikitext foo bar ! html< p >< i > foo< b > bar</b ></i ></p > !end ! test Italics and ! wikitext foo bar ! html< p >< i > foo< b > bar</b ></i ></p > !end ! test Italics and ! wikitext foo bar ! html< p >< i > foo< b > bar</b ></i ></p > !end ! test Italics and ! wikitext foo bar ! html php< p >< b > foo</b > bar</p > ! html parsoid< p >< b > foo</b > bar< i ></i ></p > !end ! test Italics and ! wikitext foo bar ! html php< p >< b > foo</b > bar</p > ! html parsoid< p >< b > foo</b > bar< b ></b ></p > !end ! test Italics and ! wikitext this is about foo s family ! html< p >< i > this is about< b > foo s family</b ></i ></p > !end ! test Italics and ! wikitext this is about foo s family ! html< p >< i > this is about< b > foo s</b > family</i ></p > !end ! test Italics and ! wikitext this is about foo s family ! html< p >< b > this is about< i > foo</i ></b >< i > s family</i ></p > !end ! test Italics and ! options ! wikitext this is about foo s family ! html< p >< i > this is about</i > foo< b > s family</b ></p > !end ! test Italics and ! wikitext this is about foo s family ! html< p >< b > this is about< i > foo s</i > family</b ></p > !end ! test Italicized possessive ! wikitext The s talk page ! html< p > The< i >< a href="/wiki/Main_Page" title="Main Page"> Main Page</a ></i > s talk page</p > ! end ! test Parsoid only
Definition: parserTests.txt:396
$rev
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Definition: hooks.txt:1337
User\idFromName
static idFromName( $name)
Get database id given a user name.
Definition: User.php:503
in
Prior to maintenance scripts were a hodgepodge of code that had no cohesion or formal method of action Beginning in
Definition: maintenance.txt:1
as
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
Block
Definition: Block.php:22
Revision\userJoinCond
static userJoinCond()
Return the value of a select() JOIN conds array for the user table.
Definition: Revision.php:386
block
this hook is for auditing only etc block
Definition: hooks.txt:1644
NS_USER
const NS_USER
Definition: Defines.php:81
$batch
$batch
Definition: linkcache.txt:23
name
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at name
Definition: design.txt:12
Revision\selectUserFields
static selectUserFields()
Return the list of user fields that should be selected from user table.
Definition: Revision.php:493
ContribsPager\getEndBody
getEndBody()
Definition: SpecialContributions.php:932
SpecialContributions\contributionsSub
contributionsSub( $userObj)
Generates the subheading with links.
Definition: SpecialContributions.php:245
change
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 change
Definition: distributors.txt:9
Html\rawElement
static rawElement( $element, $attribs=array(), $contents='')
Returns an HTML element in a string.
Definition: Html.php:121
Revision\selectFields
static selectFields()
Return the list of revision fields that should be selected to create a new revision.
Definition: Revision.php:405
ContribsPager\preventClickjacking
preventClickjacking()
Definition: SpecialContributions.php:1130
MWNamespace\getAssociated
static getAssociated( $index)
Get the associated namespace.
Definition: Namespace.php:151
SpecialContributions\__construct
__construct()
Definition: SpecialContributions.php:32
ContribsPager\getIndexField
getIndexField()
This function should be overridden to return the name of the index fi- eld.
Definition: SpecialContributions.php:895
SpecialPage\outputHeader
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
Definition: SpecialPage.php:443
SpecialPage\including
including( $x=null)
Whether the special page is being evaluated via transclusion.
Definition: SpecialPage.php:207
Revision\DELETED_TEXT
const DELETED_TEXT
Definition: Revision.php:65
SpecialContributions
Special:Contributions, show user contributions in a paged list.
Definition: SpecialContributions.php:29
IP\isIPAddress
static isIPAddress( $ip)
Determine if a string is as valid IP address or network (CIDR prefix).
Definition: IP.php:74
ChangeTags\formatSummaryRow
static formatSummaryRow( $tags, $page)
Creates HTML for the given tags.
Definition: ChangeTags.php:34
User\getGroupsWithPermission
static getGroupsWithPermission( $role)
Get all the groups who have a given permission.
Definition: User.php:4143
$e
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException' returning false will NOT prevent logging $e
Definition: hooks.txt:1632
LogEventsList\showLogExtract
static showLogExtract(&$out, $types=array(), $page='', $user='', $param=array())
Show log extract.
Definition: LogEventsList.php:507
page
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 my talk page
Definition: hooks.txt:1961