MediaWiki  master
SpecialEditWatchlist.php
Go to the documentation of this file.
1 <?php
35 
49  public const EDIT_CLEAR = 1;
50  public const EDIT_RAW = 2;
51  public const EDIT_NORMAL = 3;
52 
53  protected $successMessage;
54 
55  protected $toc;
56 
57  private $badItems = [];
58 
60  private $titleParser;
61 
64 
66  private $genderCache;
67 
70 
72  private $nsInfo;
73 
76 
79 
89  public function __construct(
94  NamespaceInfo $nsInfo = null,
97  ) {
98  parent::__construct( 'EditWatchlist', 'editmywatchlist' );
99  // This class is extended and therefor fallback to global state - T266065
100  $services = MediaWikiServices::getInstance();
101  $this->watchedItemStore = $watchedItemStore ?? $services->getWatchedItemStore();
102  $this->titleParser = $titleParser ?? $services->getTitleParser();
103  $this->genderCache = $genderCache ?? $services->getGenderCache();
104  $this->linkBatchFactory = $linkBatchFactory ?? $services->getLinkBatchFactory();
105  $this->nsInfo = $nsInfo ?? $services->getNamespaceInfo();
106  $this->wikiPageFactory = $wikiPageFactory ?? $services->getWikiPageFactory();
107  $this->watchlistManager = $watchlistManager ?? $services->getWatchlistManager();
108  }
109 
110  public function doesWrites() {
111  return true;
112  }
113 
119  public function execute( $mode ) {
120  $this->setHeaders();
121 
122  # Anons don't get a watchlist
123  $this->requireLogin( 'watchlistanontext' );
124 
125  $out = $this->getOutput();
126 
127  $this->checkPermissions();
128  $this->checkReadOnly();
129 
130  $this->outputHeader();
131  $this->outputSubtitle();
132  $out->addModuleStyles( 'mediawiki.special' );
133 
134  $mode = self::getMode( $this->getRequest(), $mode );
135 
136  switch ( $mode ) {
137  case self::EDIT_RAW:
138  $out->setPageTitle( $this->msg( 'watchlistedit-raw-title' ) );
139  $form = $this->getRawForm();
140  if ( $form->show() ) {
141  $out->addHTML( $this->successMessage );
142  $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) );
143  }
144  break;
145  case self::EDIT_CLEAR:
146  $out->setPageTitle( $this->msg( 'watchlistedit-clear-title' ) );
147  $form = $this->getClearForm();
148  if ( $form->show() ) {
149  $out->addHTML( $this->successMessage );
150  $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) );
151  }
152  break;
153 
154  case self::EDIT_NORMAL:
155  default:
156  $this->executeViewEditWatchlist();
157  break;
158  }
159  }
160 
164  protected function outputSubtitle() {
165  $out = $this->getOutput();
166  $out->addSubtitle( $this->msg( 'watchlistfor2', $this->getUser()->getName() )
167  ->rawParams(
168  self::buildTools(
169  $this->getLanguage(),
170  $this->getLinkRenderer()
171  )
172  )
173  );
174  }
175 
179  protected function executeViewEditWatchlist() {
180  $out = $this->getOutput();
181  $out->setPageTitle( $this->msg( 'watchlistedit-normal-title' ) );
182  $form = $this->getNormalForm();
183  if ( $form->show() ) {
184  $out->addHTML( $this->successMessage );
185  $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) );
186  } elseif ( $this->toc !== false ) {
187  $out->prependHTML( $this->toc );
188  }
189  }
190 
197  public function getSubpagesForPrefixSearch() {
198  // SpecialWatchlist uses SpecialEditWatchlist::getMode, so new types should be added
199  // here and there - no 'edit' here, because that the default for this page
200  return [
201  'clear',
202  'raw',
203  ];
204  }
205 
213  private function extractTitles( $list ) {
214  $list = explode( "\n", trim( $list ) );
215  if ( !is_array( $list ) ) {
216  return [];
217  }
218 
219  $titles = [];
220 
221  foreach ( $list as $text ) {
222  $text = trim( $text );
223  if ( strlen( $text ) > 0 ) {
224  $title = Title::newFromText( $text );
225  if ( $title instanceof Title && $this->watchlistManager->isWatchable( $title ) ) {
226  $titles[] = $title;
227  }
228  }
229  }
230 
231  $this->genderCache->doTitlesArray( $titles );
232 
233  $list = [];
235  foreach ( $titles as $title ) {
236  $list[] = $title->getPrefixedText();
237  }
238 
239  return array_unique( $list );
240  }
241 
242  public function submitRaw( $data ) {
243  $wanted = $this->extractTitles( $data['Titles'] );
244  $current = $this->getWatchlist();
245 
246  if ( count( $wanted ) > 0 ) {
247  $toWatch = array_diff( $wanted, $current );
248  $toUnwatch = array_diff( $current, $wanted );
249  $this->watchTitles( $toWatch );
250  $this->unwatchTitles( $toUnwatch );
251  $this->getUser()->invalidateCache();
252 
253  if ( count( $toWatch ) > 0 || count( $toUnwatch ) > 0 ) {
254  $this->successMessage = $this->msg( 'watchlistedit-raw-done' )->parse();
255  } else {
256  return false;
257  }
258 
259  if ( count( $toWatch ) > 0 ) {
260  $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-added' )
261  ->numParams( count( $toWatch ) )->parse();
262  $this->showTitles( $toWatch, $this->successMessage );
263  }
264 
265  if ( count( $toUnwatch ) > 0 ) {
266  $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-removed' )
267  ->numParams( count( $toUnwatch ) )->parse();
268  $this->showTitles( $toUnwatch, $this->successMessage );
269  }
270  } else {
271 
272  if ( count( $current ) === 0 ) {
273  return false;
274  }
275 
276  $this->clearUserWatchedItems( 'raw' );
277  $this->showTitles( $current, $this->successMessage );
278  }
279 
280  return true;
281  }
282 
289  public function submitClear( $data ): bool {
290  $this->clearUserWatchedItems( 'clear' );
291  return true;
292  }
293 
300  private function clearUserWatchedItems( string $messageFor ): void {
301  if ( $this->watchedItemStore->mustClearWatchedItemsUsingJobQueue( $this->getUser() ) ) {
303  } else {
304  $this->clearUserWatchedItemsNow( $messageFor );
305  }
306  }
307 
313  private function clearUserWatchedItemsNow( string $messageFor ): void {
314  $current = $this->getWatchlist();
315  if ( !$this->watchedItemStore->clearUserWatchedItems( $this->getUser() ) ) {
316  throw new LogicException(
317  __METHOD__ . ' should only be called when able to clear synchronously'
318  );
319  }
320  $this->successMessage = $this->msg( 'watchlistedit-' . $messageFor . '-done' )->parse();
321  $this->successMessage .= ' ' . $this->msg( 'watchlistedit-' . $messageFor . '-removed' )
322  ->numParams( count( $current ) )->parse();
323  $this->getUser()->invalidateCache();
324  $this->showTitles( $current, $this->successMessage );
325  }
326 
330  private function clearUserWatchedItemsUsingJobQueue(): void {
331  $this->watchedItemStore->clearUserWatchedItemsUsingJobQueue( $this->getUser() );
332  $this->successMessage = $this->msg( 'watchlistedit-clear-jobqueue' )->parse();
333  }
334 
344  private function showTitles( $titles, &$output ) {
345  $talk = $this->msg( 'talkpagelinktext' )->text();
346  // Do a batch existence check
347  $batch = $this->linkBatchFactory->newLinkBatch();
348  if ( count( $titles ) >= 100 ) {
349  $output = $this->msg( 'watchlistedit-too-many' )->parse();
350  return;
351  }
352  foreach ( $titles as $title ) {
353  if ( !$title instanceof Title ) {
355  }
356 
357  if ( $title instanceof Title ) {
358  $batch->addObj( $title );
359  $batch->addObj( $title->getTalkPage() );
360  }
361  }
362 
363  $batch->execute();
364 
365  // Print out the list
366  $output .= "<ul>\n";
367 
368  $linkRenderer = $this->getLinkRenderer();
369  foreach ( $titles as $title ) {
370  if ( !$title instanceof Title ) {
372  }
373 
374  if ( $title instanceof Title ) {
375  $output .= '<li>' .
376  $linkRenderer->makeLink( $title ) . ' ' .
377  $this->msg( 'parentheses' )->rawParams(
378  $linkRenderer->makeLink( $title->getTalkPage(), $talk )
379  )->escaped() .
380  "</li>\n";
381  }
382  }
383 
384  $output .= "</ul>\n";
385  }
386 
393  private function getWatchlist() {
394  $list = [];
395 
396  $watchedItems = $this->watchedItemStore->getWatchedItemsForUser(
397  $this->getUser(),
398  [ 'forWrite' => $this->getRequest()->wasPosted() ]
399  );
400 
401  if ( $watchedItems ) {
403  $titles = [];
404  foreach ( $watchedItems as $watchedItem ) {
405  $namespace = $watchedItem->getTarget()->getNamespace();
406  $dbKey = $watchedItem->getTarget()->getDBkey();
407  $title = Title::makeTitleSafe( $namespace, $dbKey );
408 
409  if ( $this->checkTitle( $title, $namespace, $dbKey )
410  && !$title->isTalkPage()
411  ) {
412  $titles[] = $title;
413  }
414  }
415 
416  $this->genderCache->doTitlesArray( $titles );
417 
418  foreach ( $titles as $title ) {
419  $list[] = $title->getPrefixedText();
420  }
421  }
422 
423  $this->cleanupWatchlist();
424 
425  return $list;
426  }
427 
434  protected function getWatchlistInfo() {
435  $titles = [];
436  $options = [ 'sort' => WatchedItemStore::SORT_ASC ];
437 
438  if ( $this->getConfig()->get( 'WatchlistExpiry' ) ) {
439  $options[ 'sortByExpiry'] = true;
440  }
441 
442  $watchedItems = $this->watchedItemStore->getWatchedItemsForUser(
443  $this->getUser(), $options
444  );
445 
446  $lb = $this->linkBatchFactory->newLinkBatch();
447  $context = $this->getContext();
448 
449  foreach ( $watchedItems as $watchedItem ) {
450  $namespace = $watchedItem->getTarget()->getNamespace();
451  $dbKey = $watchedItem->getTarget()->getDBkey();
452  $lb->add( $namespace, $dbKey );
453  if ( !$this->nsInfo->isTalk( $namespace ) ) {
454  $titles[$namespace][$dbKey] = $watchedItem->getExpiryInDaysText( $context );
455  }
456  }
457 
458  $lb->execute();
459 
460  return $titles;
461  }
462 
471  private function checkTitle( $title, $namespace, $dbKey ) {
472  if ( $title
473  && ( $title->isExternal()
474  || $title->getNamespace() < 0
475  )
476  ) {
477  $title = false; // unrecoverable
478  }
479 
480  if ( !$title
481  || $title->getNamespace() != $namespace
482  || $title->getDBkey() != $dbKey
483  ) {
484  $this->badItems[] = [ $title, $namespace, $dbKey ];
485  }
486 
487  return (bool)$title;
488  }
489 
493  private function cleanupWatchlist() {
494  if ( $this->badItems === [] ) {
495  return; // nothing to do
496  }
497 
498  $user = $this->getUser();
500  DeferredUpdates::addCallableUpdate( function () use ( $user, $badItems ) {
501  foreach ( $badItems as [ $title, $namespace, $dbKey ] ) {
502  $action = $title ? 'cleaning up' : 'deleting';
503  wfDebug( "User {$user->getName()} has broken watchlist item " .
504  "ns($namespace):$dbKey, $action." );
505 
506  // NOTE: We *know* that the title is invalid. TitleValue may refuse instantiation.
507  // XXX: We may need an InvalidTitleValue class that allows instantiation of
508  // known bad title values.
509  $this->watchedItemStore->removeWatch( $user, Title::makeTitle( (int)$namespace, $dbKey ) );
510  // Can't just do an UPDATE instead of DELETE/INSERT due to unique index
511  if ( $title ) {
512  $this->watchlistManager->addWatch( $user, $title );
513  }
514  }
515  } );
516  }
517 
526  private function watchTitles( array $targets ) {
527  return $this->watchedItemStore->addWatchBatchForUser(
528  $this->getUser(), $this->getExpandedTargets( $targets )
529  ) && $this->runWatchUnwatchCompleteHook( 'Watch', $targets );
530  }
531 
544  private function unwatchTitles( array $targets ) {
545  return $this->watchedItemStore->removeWatchBatchForUser(
546  $this->getUser(), $this->getExpandedTargets( $targets )
547  ) && $this->runWatchUnwatchCompleteHook( 'Unwatch', $targets );
548  }
549 
558  private function runWatchUnwatchCompleteHook( $action, $targets ) {
559  foreach ( $targets as $target ) {
560  $title = $target instanceof LinkTarget ?
561  Title::newFromLinkTarget( $target ) :
562  Title::newFromText( $target );
563  $page = $this->wikiPageFactory->newFromTitle( $title );
564  $user = $this->getUser();
565  if ( $action === 'Watch' ) {
566  $this->getHookRunner()->onWatchArticleComplete( $user, $page );
567  } else {
568  $this->getHookRunner()->onUnwatchArticleComplete( $user, $page );
569  }
570  }
571  return true;
572  }
573 
578  private function getExpandedTargets( array $targets ) {
579  $expandedTargets = [];
580  foreach ( $targets as $target ) {
581  if ( !$target instanceof LinkTarget ) {
582  try {
583  $target = $this->titleParser->parseTitle( $target, NS_MAIN );
584  }
585  catch ( MalformedTitleException $e ) {
586  continue;
587  }
588  }
589 
590  $ns = $target->getNamespace();
591  $dbKey = $target->getDBkey();
592  $expandedTargets[] =
593  new TitleValue( $this->nsInfo->getSubject( $ns ), $dbKey );
594  $expandedTargets[] =
595  new TitleValue( $this->nsInfo->getTalk( $ns ), $dbKey );
596  }
597  return $expandedTargets;
598  }
599 
600  public function submitNormal( $data ) {
601  $removed = [];
602 
603  foreach ( $data as $titles ) {
604  $this->unwatchTitles( $titles );
605  $removed = array_merge( $removed, $titles );
606  }
607 
608  if ( count( $removed ) > 0 ) {
609  $this->successMessage = $this->msg( 'watchlistedit-normal-done'
610  )->numParams( count( $removed ) )->parse();
611  $this->showTitles( $removed, $this->successMessage );
612 
613  return true;
614  } else {
615  return false;
616  }
617  }
618 
624  protected function getNormalForm() {
625  $fields = [];
626  $count = 0;
627 
628  // Allow subscribers to manipulate the list of watched pages (or use it
629  // to preload lots of details at once)
630  $watchlistInfo = $this->getWatchlistInfo();
631  $this->getHookRunner()->onWatchlistEditorBeforeFormRender( $watchlistInfo );
632 
633  foreach ( $watchlistInfo as $namespace => $pages ) {
634  $options = [];
635  foreach ( $pages as $dbkey => $expiryDaysText ) {
636  $title = Title::makeTitleSafe( $namespace, $dbkey );
637 
638  if ( $this->checkTitle( $title, $namespace, $dbkey ) ) {
639  $text = $this->buildRemoveLine( $title, $expiryDaysText );
640  $options[$text] = $title->getPrefixedText();
641  $count++;
642  }
643  }
644 
645  // checkTitle can filter some options out, avoid empty sections
646  if ( count( $options ) > 0 ) {
647  $fields['TitlesNs' . $namespace] = [
648  'class' => EditWatchlistCheckboxSeriesField::class,
649  'options' => $options,
650  'section' => "ns$namespace",
651  ];
652  }
653  }
654  $this->cleanupWatchlist();
655 
656  if ( count( $fields ) > 1 && $count > 30 ) {
657  $this->toc = Linker::tocIndent();
658  $tocLength = 0;
659  $contLang = $this->getContentLanguage();
660 
661  foreach ( $fields as $data ) {
662  # strip out the 'ns' prefix from the section name:
663  $ns = substr( $data['section'], 2 );
664 
665  $nsText = ( $ns == NS_MAIN )
666  ? $this->msg( 'blanknamespace' )->escaped()
667  : htmlspecialchars( $contLang->getFormattedNsText( $ns ) );
668  $this->toc .= Linker::tocLine( "editwatchlist-{$data['section']}", $nsText,
669  $this->getLanguage()->formatNum( ++$tocLength ), 1 ) . Linker::tocLineEnd();
670  }
671 
672  $this->toc = Linker::tocList( $this->toc );
673  } else {
674  $this->toc = false;
675  }
676 
677  $context = new DerivativeContext( $this->getContext() );
678  $context->setTitle( $this->getPageTitle() ); // Remove subpage
679  $form = new EditWatchlistNormalHTMLForm( $fields, $context );
680  $form->setSubmitTextMsg( 'watchlistedit-normal-submit' );
681  $form->setSubmitDestructive();
682  # Used message keys:
683  # 'accesskey-watchlistedit-normal-submit', 'tooltip-watchlistedit-normal-submit'
684  $form->setSubmitTooltip( 'watchlistedit-normal-submit' );
685  $form->setWrapperLegendMsg( 'watchlistedit-normal-legend' );
686  $form->addHeaderText( $this->msg( 'watchlistedit-normal-explain' )->parse() );
687  $form->setSubmitCallback( [ $this, 'submitNormal' ] );
688 
689  return $form;
690  }
691 
700  private function buildRemoveLine( $title, string $expiryDaysText = '' ): string {
701  $linkRenderer = $this->getLinkRenderer();
702  $link = $linkRenderer->makeLink( $title );
703 
704  $tools = [];
705  $tools['talk'] = $linkRenderer->makeLink(
706  $title->getTalkPage(),
707  $this->msg( 'talkpagelinktext' )->text()
708  );
709 
710  if ( $title->exists() ) {
711  $tools['history'] = $linkRenderer->makeKnownLink(
712  $title,
713  $this->msg( 'history_small' )->text(),
714  [],
715  [ 'action' => 'history' ]
716  );
717  }
718 
719  if ( $title->getNamespace() === NS_USER && !$title->isSubpage() ) {
720  $tools['contributions'] = $linkRenderer->makeKnownLink(
721  SpecialPage::getTitleFor( 'Contributions', $title->getText() ),
722  $this->msg( 'contribslink' )->text()
723  );
724  }
725 
726  $this->getHookRunner()->onWatchlistEditorBuildRemoveLine(
727  $tools, $title, $title->isRedirect(), $this->getSkin(), $link );
728 
729  if ( $title->isRedirect() ) {
730  // Linker already makes class mw-redirect, so this is redundant
731  $link = '<span class="watchlistredir">' . $link . '</span>';
732  }
733 
734  $watchlistExpiringMessage = '';
735  if ( $this->getConfig()->get( 'WatchlistExpiry' ) && $expiryDaysText ) {
736  $watchlistExpiringMessage = Html::element(
737  'span',
738  [ 'class' => 'mw-watchlistexpiry-msg' ],
739  $expiryDaysText
740  );
741  }
742 
743  return $link . ' ' .
744  $this->msg( 'parentheses' )->rawParams( $this->getLanguage()->pipeList( $tools ) )->escaped() .
745  $watchlistExpiringMessage;
746  }
747 
753  protected function getRawForm() {
754  $titles = implode( "\n", $this->getWatchlist() );
755  $fields = [
756  'Titles' => [
757  'type' => 'textarea',
758  'label-message' => 'watchlistedit-raw-titles',
759  'default' => $titles,
760  ],
761  ];
762  $context = new DerivativeContext( $this->getContext() );
763  $context->setTitle( $this->getPageTitle( 'raw' ) ); // Reset subpage
764  $form = new OOUIHTMLForm( $fields, $context );
765  $form->setSubmitTextMsg( 'watchlistedit-raw-submit' );
766  # Used message keys: 'accesskey-watchlistedit-raw-submit', 'tooltip-watchlistedit-raw-submit'
767  $form->setSubmitTooltip( 'watchlistedit-raw-submit' );
768  $form->setWrapperLegendMsg( 'watchlistedit-raw-legend' );
769  $form->addHeaderText( $this->msg( 'watchlistedit-raw-explain' )->parse() );
770  $form->setSubmitCallback( [ $this, 'submitRaw' ] );
771 
772  return $form;
773  }
774 
780  protected function getClearForm() {
781  $context = new DerivativeContext( $this->getContext() );
782  $context->setTitle( $this->getPageTitle( 'clear' ) ); // Reset subpage
783  $form = new OOUIHTMLForm( [], $context );
784  $form->setSubmitTextMsg( 'watchlistedit-clear-submit' );
785  # Used message keys: 'accesskey-watchlistedit-clear-submit', 'tooltip-watchlistedit-clear-submit'
786  $form->setSubmitTooltip( 'watchlistedit-clear-submit' );
787  $form->setWrapperLegendMsg( 'watchlistedit-clear-legend' );
788  $form->addHeaderText( $this->msg( 'watchlistedit-clear-explain' )->parse() );
789  $form->setSubmitCallback( [ $this, 'submitClear' ] );
790  $form->setSubmitDestructive();
791 
792  return $form;
793  }
794 
803  public static function getMode( $request, $par ) {
804  $mode = strtolower( $request->getRawVal( 'action', $par ) );
805 
806  switch ( $mode ) {
807  case 'clear':
808  case self::EDIT_CLEAR:
809  return self::EDIT_CLEAR;
810  case 'raw':
811  case self::EDIT_RAW:
812  return self::EDIT_RAW;
813  case 'edit':
814  case self::EDIT_NORMAL:
815  return self::EDIT_NORMAL;
816  default:
817  return false;
818  }
819  }
820 
829  public static function buildTools( $lang, LinkRenderer $linkRenderer = null ) {
830  if ( !$lang instanceof Language ) {
831  // back-compat where the first parameter was $unused
832  global $wgLang;
833  $lang = $wgLang;
834  }
835  if ( !$linkRenderer ) {
836  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
837  }
838 
839  $tools = [];
840  $modes = [
841  'view' => [ 'Watchlist', false ],
842  'edit' => [ 'EditWatchlist', false ],
843  'raw' => [ 'EditWatchlist', 'raw' ],
844  'clear' => [ 'EditWatchlist', 'clear' ],
845  ];
846 
847  foreach ( $modes as $mode => $arr ) {
848  // can use messages 'watchlisttools-view', 'watchlisttools-edit', 'watchlisttools-raw'
849  $tools[] = $linkRenderer->makeKnownLink(
850  SpecialPage::getTitleFor( $arr[0], $arr[1] ),
851  wfMessage( "watchlisttools-{$mode}" )->text()
852  );
853  }
854 
855  return Html::rawElement(
856  'span',
857  [ 'class' => 'mw-watchlist-toollinks' ],
858  wfMessage( 'parentheses' )->rawParams( $lang->pipeList( $tools ) )->escaped()
859  );
860  }
861 }
SpecialPage\$linkRenderer
LinkRenderer null $linkRenderer
Definition: SpecialPage.php:80
SpecialPage\getPageTitle
getPageTitle( $subpage=false)
Get a self-referential title object.
Definition: SpecialPage.php:744
SpecialEditWatchlist\submitNormal
submitNormal( $data)
Definition: SpecialEditWatchlist.php:600
SpecialEditWatchlist\EDIT_CLEAR
const EDIT_CLEAR
Editing modes.
Definition: SpecialEditWatchlist.php:49
SpecialEditWatchlist\unwatchTitles
unwatchTitles(array $targets)
Remove a list of titles from a user's watchlist.
Definition: SpecialEditWatchlist.php:544
SpecialEditWatchlist\getWatchlist
getWatchlist()
Prepare a list of titles on a user's watchlist (excluding talk pages) and return an array of (prefixe...
Definition: SpecialEditWatchlist.php:393
SpecialEditWatchlist\$watchedItemStore
WatchedItemStoreInterface $watchedItemStore
Definition: SpecialEditWatchlist.php:63
SpecialPage\msg
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:912
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:395
SpecialEditWatchlist\$nsInfo
NamespaceInfo $nsInfo
Definition: SpecialEditWatchlist.php:72
SpecialEditWatchlist\EDIT_RAW
const EDIT_RAW
Definition: SpecialEditWatchlist.php:50
SpecialEditWatchlist\checkTitle
checkTitle( $title, $namespace, $dbKey)
Validates watchlist entry.
Definition: SpecialEditWatchlist.php:471
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:790
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:200
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
UnlistedSpecialPage
Shortcut to construct a special page which is unlisted by default.
Definition: UnlistedSpecialPage.php:31
Linker\tocIndent
static tocIndent()
Add another level to the Table of Contents.
Definition: Linker.php:1561
MediaWiki\Linker\LinkRenderer
Class that generates HTML links for pages.
Definition: LinkRenderer.php:43
SpecialEditWatchlist\submitRaw
submitRaw( $data)
Definition: SpecialEditWatchlist.php:242
SpecialPage\checkPermissions
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
Definition: SpecialPage.php:358
GenderCache
Caches user genders when needed to use correct namespace aliases.
Definition: GenderCache.php:36
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1183
SpecialPage\getTitleFor
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:107
SpecialEditWatchlist\watchTitles
watchTitles(array $targets)
Add a list of targets to a user's watchlist.
Definition: SpecialEditWatchlist.php:526
SpecialEditWatchlist\$linkBatchFactory
LinkBatchFactory $linkBatchFactory
Definition: SpecialEditWatchlist.php:69
SpecialEditWatchlist\getExpandedTargets
getExpandedTargets(array $targets)
Definition: SpecialEditWatchlist.php:578
SpecialPage\getLanguage
getLanguage()
Shortcut to get user's language.
Definition: SpecialPage.php:830
SpecialPage\getName
getName()
Get the name of this Special Page.
Definition: SpecialPage.php:179
Linker\tocLine
static tocLine( $anchor, $tocline, $tocnumber, $level, $sectionIndex=false)
parameter level defines if we are on an indentation level
Definition: Linker.php:1587
$wgLang
$wgLang
Definition: Setup.php:851
SpecialEditWatchlist\$badItems
$badItems
Definition: SpecialEditWatchlist.php:57
Linker\tocList
static tocList( $toc, Language $lang=null)
Wraps the TOC in a div with ARIA navigation role and provides the hide/collapse JavaScript.
Definition: Linker.php:1623
SpecialEditWatchlist\clearUserWatchedItemsNow
clearUserWatchedItemsNow(string $messageFor)
You should call clearUserWatchedItems() instead to decide if this should use the JobQueue.
Definition: SpecialEditWatchlist.php:313
SpecialEditWatchlist\$titleParser
TitleParser $titleParser
Definition: SpecialEditWatchlist.php:60
NS_MAIN
const NS_MAIN
Definition: Defines.php:64
SpecialEditWatchlist\runWatchUnwatchCompleteHook
runWatchUnwatchCompleteHook( $action, $targets)
Definition: SpecialEditWatchlist.php:558
SpecialEditWatchlist\clearUserWatchedItemsUsingJobQueue
clearUserWatchedItemsUsingJobQueue()
You should call clearUserWatchedItems() instead to decide if this should use the JobQueue.
Definition: SpecialEditWatchlist.php:330
OOUIHTMLForm
Compact stacked vertical format for forms, implemented using OOUI widgets.
Definition: OOUIHTMLForm.php:29
SpecialEditWatchlist\execute
execute( $mode)
Main execution point.
Definition: SpecialEditWatchlist.php:119
EditWatchlistNormalHTMLForm
Extend OOUIHTMLForm purely so we can have a more sensible way of getting the section headers.
Definition: EditWatchlistNormalHTMLForm.php:24
DerivativeContext
An IContextSource implementation which will inherit context from another source but allow individual ...
Definition: DerivativeContext.php:32
SpecialEditWatchlist\EDIT_NORMAL
const EDIT_NORMAL
Definition: SpecialEditWatchlist.php:51
SpecialPage\getHookRunner
getHookRunner()
Definition: SpecialPage.php:1095
SpecialPage\getConfig
getConfig()
Shortcut to get main config object.
Definition: SpecialPage.php:878
SpecialEditWatchlist\$wikiPageFactory
WikiPageFactory $wikiPageFactory
Definition: SpecialEditWatchlist.php:75
MediaWiki\Watchlist\WatchlistManager
WatchlistManager service.
Definition: WatchlistManager.php:52
SpecialEditWatchlist\getRawForm
getRawForm()
Get a form for editing the watchlist in "raw" mode.
Definition: SpecialEditWatchlist.php:753
MediaWiki\Cache\LinkBatchFactory
Definition: LinkBatchFactory.php:39
SpecialEditWatchlist\executeViewEditWatchlist
executeViewEditWatchlist()
Executes an edit mode for the watchlist view, from which you can manage your watchlist.
Definition: SpecialEditWatchlist.php:179
SpecialEditWatchlist\extractTitles
extractTitles( $list)
Extract a list of titles from a blob of text, returning (prefixed) strings; unwatchable titles are ig...
Definition: SpecialEditWatchlist.php:213
Linker\tocLineEnd
static tocLineEnd()
End a Table Of Contents line.
Definition: Linker.php:1611
SpecialEditWatchlist
Provides the UI through which users can perform editing operations on their watchlist.
Definition: SpecialEditWatchlist.php:44
Page\WikiPageFactory
Definition: WikiPageFactory.php:19
SpecialEditWatchlist\$genderCache
GenderCache $genderCache
Definition: SpecialEditWatchlist.php:66
$title
$title
Definition: testCompression.php:38
SpecialPage\setHeaders
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
Definition: SpecialPage.php:618
SpecialPage\getUser
getUser()
Shortcut to get the User executing this instance.
Definition: SpecialPage.php:800
SpecialEditWatchlist\showTitles
showTitles( $titles, &$output)
Print out a list of linked titles.
Definition: SpecialEditWatchlist.php:344
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:663
TitleParser
A title parser service for MediaWiki.
Definition: TitleParser.php:33
SpecialEditWatchlist\$watchlistManager
WatchlistManager $watchlistManager
Definition: SpecialEditWatchlist.php:78
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:894
SpecialEditWatchlist\__construct
__construct(WatchedItemStoreInterface $watchedItemStore=null, TitleParser $titleParser=null, GenderCache $genderCache=null, LinkBatchFactory $linkBatchFactory=null, NamespaceInfo $nsInfo=null, WikiPageFactory $wikiPageFactory=null, WatchlistManager $watchlistManager=null)
Definition: SpecialEditWatchlist.php:89
SpecialPage\getContext
getContext()
Gets the context this SpecialPage is executed in.
Definition: SpecialPage.php:764
SpecialPage\requireLogin
requireLogin( $reasonMsg='exception-nologin-text', $titleMsg='exception-nologin')
If the user is not logged in, throws UserNotLoggedIn error.
Definition: SpecialPage.php:388
MediaWiki\Linker\LinkRenderer\makeKnownLink
makeKnownLink( $target, $text=null, array $extraAttribs=[], array $query=[])
Definition: LinkRenderer.php:236
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:689
SpecialEditWatchlist\getMode
static getMode( $request, $par)
Determine whether we are editing the watchlist, and if so, what kind of editing operation.
Definition: SpecialEditWatchlist.php:803
SpecialEditWatchlist\getSubpagesForPrefixSearch
getSubpagesForPrefixSearch()
Return an array of subpages that this special page will accept.
Definition: SpecialEditWatchlist.php:197
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:780
SpecialEditWatchlist\cleanupWatchlist
cleanupWatchlist()
Attempts to clean up broken items.
Definition: SpecialEditWatchlist.php:493
SpecialEditWatchlist\doesWrites
doesWrites()
Indicates whether this special page may perform database writes.
Definition: SpecialEditWatchlist.php:110
WatchedItemStoreInterface\SORT_ASC
const SORT_ASC
Definition: WatchedItemStoreInterface.php:36
NS_USER
const NS_USER
Definition: Defines.php:66
SpecialEditWatchlist\buildRemoveLine
buildRemoveLine( $title, string $expiryDaysText='')
Build the label for a checkbox, with a link to the title, and various additional bits.
Definition: SpecialEditWatchlist.php:700
Title\newFromLinkTarget
static newFromLinkTarget(LinkTarget $linkTarget, $forceClone='')
Returns a Title given a LinkTarget.
Definition: Title.php:307
SpecialEditWatchlist\outputSubtitle
outputSubtitle()
Renders a subheader on the watchlist page.
Definition: SpecialEditWatchlist.php:164
SpecialEditWatchlist\$toc
$toc
Definition: SpecialEditWatchlist.php:55
SpecialPage\getLinkRenderer
getLinkRenderer()
Definition: SpecialPage.php:1028
SpecialEditWatchlist\buildTools
static buildTools( $lang, LinkRenderer $linkRenderer=null)
Build a set of links for convenient navigation between watchlist viewing and editing modes.
Definition: SpecialEditWatchlist.php:829
Title
Represents a title within MediaWiki.
Definition: Title.php:47
SpecialEditWatchlist\getClearForm
getClearForm()
Get a form for clearing the watchlist.
Definition: SpecialEditWatchlist.php:780
MalformedTitleException
MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
Definition: MalformedTitleException.php:26
SpecialEditWatchlist\clearUserWatchedItems
clearUserWatchedItems(string $messageFor)
Makes a decision about using the JobQueue or not for clearing a users watchlist.
Definition: SpecialEditWatchlist.php:300
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:210
SpecialEditWatchlist\getNormalForm
getNormalForm()
Get the standard watchlist editing form.
Definition: SpecialEditWatchlist.php:624
NamespaceInfo
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Definition: NamespaceInfo.php:35
SpecialPage\getContentLanguage
getContentLanguage()
Shortcut to get content language.
Definition: SpecialPage.php:840
SpecialPage\checkReadOnly
checkReadOnly()
If the wiki is currently in readonly mode, throws a ReadOnlyError.
Definition: SpecialPage.php:371
Html\element
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:232
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
SpecialEditWatchlist\getWatchlistInfo
getWatchlistInfo()
Get a list of titles on a user's watchlist, excluding talk pages, and return as a two-dimensional arr...
Definition: SpecialEditWatchlist.php:434
WatchedItemStoreInterface
Definition: WatchedItemStoreInterface.php:31
DeferredUpdates\addCallableUpdate
static addCallableUpdate( $callable, $stage=self::POSTSEND, $dbw=null)
Add an update to the pending update queue that invokes the specified callback when run.
Definition: DeferredUpdates.php:145
SpecialEditWatchlist\submitClear
submitClear( $data)
Handler for the clear form submission.
Definition: SpecialEditWatchlist.php:289
MediaWiki\Linker\LinkRenderer\makeLink
makeLink( $target, $text=null, array $extraAttribs=[], array $query=[])
Definition: LinkRenderer.php:169
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:709
Language
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:42
SpecialEditWatchlist\$successMessage
$successMessage
Definition: SpecialEditWatchlist.php:53
TitleValue
Represents a page (or page fragment) title within MediaWiki.
Definition: TitleValue.php:40