MediaWiki  master
SpecialEditWatchlist.php
Go to the documentation of this file.
1 <?php
32 
46  public const EDIT_CLEAR = 1;
47  public const EDIT_RAW = 2;
48  public const EDIT_NORMAL = 3;
49 
50  protected $successMessage;
51 
52  protected $toc;
53 
54  private $badItems = [];
55 
59  private $titleParser;
60 
65 
67  parent::__construct( 'EditWatchlist', 'editmywatchlist' );
68  $this->watchedItemStore = $watchedItemStore;
69  }
70 
75  private function initServices() {
76  if ( !$this->titleParser ) {
77  $this->titleParser = MediaWikiServices::getInstance()->getTitleParser();
78  }
79  }
80 
81  public function doesWrites() {
82  return true;
83  }
84 
90  public function execute( $mode ) {
91  $this->initServices();
92  $this->setHeaders();
93 
94  # Anons don't get a watchlist
95  $this->requireLogin( 'watchlistanontext' );
96 
97  $out = $this->getOutput();
98 
99  $this->checkPermissions();
100  $this->checkReadOnly();
101 
102  $this->outputHeader();
103  $this->outputSubtitle();
104  $out->addModuleStyles( 'mediawiki.special' );
105 
106  # B/C: $mode used to be waaay down the parameter list, and the first parameter
107  # was $wgUser
108  if ( $mode instanceof User ) {
109  $args = func_get_args();
110  if ( count( $args ) >= 4 ) {
111  $mode = $args[3];
112  }
113  }
114  $mode = self::getMode( $this->getRequest(), $mode );
115 
116  switch ( $mode ) {
117  case self::EDIT_RAW:
118  $out->setPageTitle( $this->msg( 'watchlistedit-raw-title' ) );
119  $form = $this->getRawForm();
120  if ( $form->show() ) {
121  $out->addHTML( $this->successMessage );
122  $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) );
123  }
124  break;
125  case self::EDIT_CLEAR:
126  $out->setPageTitle( $this->msg( 'watchlistedit-clear-title' ) );
127  $form = $this->getClearForm();
128  if ( $form->show() ) {
129  $out->addHTML( $this->successMessage );
130  $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) );
131  }
132  break;
133 
134  case self::EDIT_NORMAL:
135  default:
136  $this->executeViewEditWatchlist();
137  break;
138  }
139  }
140 
144  protected function outputSubtitle() {
145  $out = $this->getOutput();
146  $out->addSubtitle( $this->msg( 'watchlistfor2', $this->getUser()->getName() )
147  ->rawParams(
148  self::buildTools(
149  $this->getLanguage(),
150  $this->getLinkRenderer()
151  )
152  )
153  );
154  }
155 
159  protected function executeViewEditWatchlist() {
160  $out = $this->getOutput();
161  $out->setPageTitle( $this->msg( 'watchlistedit-normal-title' ) );
162  $form = $this->getNormalForm();
163  if ( $form->show() ) {
164  $out->addHTML( $this->successMessage );
165  $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) );
166  } elseif ( $this->toc !== false ) {
167  $out->prependHTML( $this->toc );
168  $out->addModuleStyles( 'mediawiki.toc.styles' );
169  }
170  }
171 
178  public function getSubpagesForPrefixSearch() {
179  // SpecialWatchlist uses SpecialEditWatchlist::getMode, so new types should be added
180  // here and there - no 'edit' here, because that the default for this page
181  return [
182  'clear',
183  'raw',
184  ];
185  }
186 
194  private function extractTitles( $list ) {
195  $list = explode( "\n", trim( $list ) );
196  if ( !is_array( $list ) ) {
197  return [];
198  }
199 
200  $titles = [];
201 
202  foreach ( $list as $text ) {
203  $text = trim( $text );
204  if ( strlen( $text ) > 0 ) {
205  $title = Title::newFromText( $text );
206  if ( $title instanceof Title && $title->isWatchable() ) {
207  $titles[] = $title;
208  }
209  }
210  }
211 
212  MediaWikiServices::getInstance()->getGenderCache()->doTitlesArray( $titles );
213 
214  $list = [];
216  foreach ( $titles as $title ) {
217  $list[] = $title->getPrefixedText();
218  }
219 
220  return array_unique( $list );
221  }
222 
223  public function submitRaw( $data ) {
224  $wanted = $this->extractTitles( $data['Titles'] );
225  $current = $this->getWatchlist();
226 
227  if ( count( $wanted ) > 0 ) {
228  $toWatch = array_diff( $wanted, $current );
229  $toUnwatch = array_diff( $current, $wanted );
230  $this->watchTitles( $toWatch );
231  $this->unwatchTitles( $toUnwatch );
232  $this->getUser()->invalidateCache();
233 
234  if ( count( $toWatch ) > 0 || count( $toUnwatch ) > 0 ) {
235  $this->successMessage = $this->msg( 'watchlistedit-raw-done' )->parse();
236  } else {
237  return false;
238  }
239 
240  if ( count( $toWatch ) > 0 ) {
241  $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-added' )
242  ->numParams( count( $toWatch ) )->parse();
243  $this->showTitles( $toWatch, $this->successMessage );
244  }
245 
246  if ( count( $toUnwatch ) > 0 ) {
247  $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-removed' )
248  ->numParams( count( $toUnwatch ) )->parse();
249  $this->showTitles( $toUnwatch, $this->successMessage );
250  }
251  } else {
252 
253  if ( count( $current ) === 0 ) {
254  return false;
255  }
256 
257  $this->clearUserWatchedItems( 'raw' );
258  $this->showTitles( $current, $this->successMessage );
259  }
260 
261  return true;
262  }
263 
270  public function submitClear( $data ): bool {
271  $this->clearUserWatchedItems( 'clear' );
272  return true;
273  }
274 
281  private function clearUserWatchedItems( string $messageFor ): void {
282  if ( $this->watchedItemStore->mustClearWatchedItemsUsingJobQueue( $this->getUser() ) ) {
284  } else {
285  $this->clearUserWatchedItemsNow( $messageFor );
286  }
287  }
288 
294  private function clearUserWatchedItemsNow( string $messageFor ): void {
295  $current = $this->getWatchlist();
296  if ( !$this->watchedItemStore->clearUserWatchedItems( $this->getUser() ) ) {
297  throw new LogicException(
298  __METHOD__ . ' should only be called when able to clear synchronously'
299  );
300  }
301  $this->successMessage = $this->msg( 'watchlistedit-' . $messageFor . '-done' )->parse();
302  $this->successMessage .= ' ' . $this->msg( 'watchlistedit-' . $messageFor . '-removed' )
303  ->numParams( count( $current ) )->parse();
304  $this->getUser()->invalidateCache();
305  $this->showTitles( $current, $this->successMessage );
306  }
307 
311  private function clearUserWatchedItemsUsingJobQueue(): void {
312  $this->watchedItemStore->clearUserWatchedItemsUsingJobQueue( $this->getUser() );
313  $this->successMessage = $this->msg( 'watchlistedit-clear-jobqueue' )->parse();
314  }
315 
325  private function showTitles( $titles, &$output ) {
326  $talk = $this->msg( 'talkpagelinktext' )->text();
327  // Do a batch existence check
328  $batch = new LinkBatch();
329  if ( count( $titles ) >= 100 ) {
330  $output = $this->msg( 'watchlistedit-too-many' )->parse();
331  return;
332  }
333  foreach ( $titles as $title ) {
334  if ( !$title instanceof Title ) {
336  }
337 
338  if ( $title instanceof Title ) {
339  $batch->addObj( $title );
340  $batch->addObj( $title->getTalkPage() );
341  }
342  }
343 
344  $batch->execute();
345 
346  // Print out the list
347  $output .= "<ul>\n";
348 
349  $linkRenderer = $this->getLinkRenderer();
350  foreach ( $titles as $title ) {
351  if ( !$title instanceof Title ) {
353  }
354 
355  if ( $title instanceof Title ) {
356  $output .= '<li>' .
357  $linkRenderer->makeLink( $title ) . ' ' .
358  $this->msg( 'parentheses' )->rawParams(
359  $linkRenderer->makeLink( $title->getTalkPage(), $talk )
360  )->escaped() .
361  "</li>\n";
362  }
363  }
364 
365  $output .= "</ul>\n";
366  }
367 
374  private function getWatchlist() {
375  $list = [];
376 
377  $watchedItems = $this->watchedItemStore->getWatchedItemsForUser(
378  $this->getUser(),
379  [ 'forWrite' => $this->getRequest()->wasPosted() ]
380  );
381 
382  if ( $watchedItems ) {
384  $titles = [];
385  foreach ( $watchedItems as $watchedItem ) {
386  $namespace = $watchedItem->getLinkTarget()->getNamespace();
387  $dbKey = $watchedItem->getLinkTarget()->getDBkey();
388  $title = Title::makeTitleSafe( $namespace, $dbKey );
389 
390  if ( $this->checkTitle( $title, $namespace, $dbKey )
391  && !$title->isTalkPage()
392  ) {
393  $titles[] = $title;
394  }
395  }
396 
397  MediaWikiServices::getInstance()->getGenderCache()->doTitlesArray( $titles );
398 
399  foreach ( $titles as $title ) {
400  $list[] = $title->getPrefixedText();
401  }
402  }
403 
404  $this->cleanupWatchlist();
405 
406  return $list;
407  }
408 
415  protected function getWatchlistInfo() {
416  $titles = [];
417  $services = MediaWikiServices::getInstance();
418 
419  $watchedItems = $this->watchedItemStore->getWatchedItemsForUser(
420  $this->getUser(), [ 'sort' => WatchedItemStore::SORT_ASC ]
421  );
422 
423  $lb = new LinkBatch();
424 
425  foreach ( $watchedItems as $watchedItem ) {
426  $namespace = $watchedItem->getLinkTarget()->getNamespace();
427  $dbKey = $watchedItem->getLinkTarget()->getDBkey();
428  $lb->add( $namespace, $dbKey );
429  if ( !$services->getNamespaceInfo()->isTalk( $namespace ) ) {
430  $titles[$namespace][$dbKey] = 1;
431  }
432  }
433 
434  $lb->execute();
435 
436  return $titles;
437  }
438 
447  private function checkTitle( $title, $namespace, $dbKey ) {
448  if ( $title
449  && ( $title->isExternal()
450  || $title->getNamespace() < 0
451  )
452  ) {
453  $title = false; // unrecoverable
454  }
455 
456  if ( !$title
457  || $title->getNamespace() != $namespace
458  || $title->getDBkey() != $dbKey
459  ) {
460  $this->badItems[] = [ $title, $namespace, $dbKey ];
461  }
462 
463  return (bool)$title;
464  }
465 
469  private function cleanupWatchlist() {
470  if ( $this->badItems === [] ) {
471  return; // nothing to do
472  }
473 
474  $user = $this->getUser();
476  DeferredUpdates::addCallableUpdate( function () use ( $user, $badItems ) {
477  foreach ( $badItems as $row ) {
478  list( $title, $namespace, $dbKey ) = $row;
479  $action = $title ? 'cleaning up' : 'deleting';
480  wfDebug( "User {$user->getName()} has broken watchlist item " .
481  "ns($namespace):$dbKey, $action." );
482 
483  // NOTE: We *know* that the title is invalid. TitleValue may refuse instantiation.
484  // XXX: We may need an InvalidTitleValue class that allows instantiation of
485  // known bad title values.
486  $this->watchedItemStore->removeWatch( $user, Title::makeTitle( (int)$namespace, $dbKey ) );
487  // Can't just do an UPDATE instead of DELETE/INSERT due to unique index
488  if ( $title ) {
489  $user->addWatch( $title );
490  }
491  }
492  } );
493  }
494 
503  private function watchTitles( array $targets ) {
504  return $this->watchedItemStore->addWatchBatchForUser(
505  $this->getUser(), $this->getExpandedTargets( $targets )
506  ) && $this->runWatchUnwatchCompleteHook( 'Watch', $targets );
507  }
508 
521  private function unwatchTitles( array $targets ) {
522  return $this->watchedItemStore->removeWatchBatchForUser(
523  $this->getUser(), $this->getExpandedTargets( $targets )
524  ) && $this->runWatchUnwatchCompleteHook( 'Unwatch', $targets );
525  }
526 
535  private function runWatchUnwatchCompleteHook( $action, $targets ) {
536  foreach ( $targets as $target ) {
537  $title = $target instanceof TitleValue ?
538  Title::newFromTitleValue( $target ) :
539  Title::newFromText( $target );
540  $page = WikiPage::factory( $title );
541  $user = $this->getUser();
542  if ( $action === 'Watch' ) {
543  $this->getHookRunner()->onWatchArticleComplete( $user, $page );
544  } else {
545  $this->getHookRunner()->onUnwatchArticleComplete( $user, $page );
546  }
547  }
548  return true;
549  }
550 
555  private function getExpandedTargets( array $targets ) {
556  $expandedTargets = [];
557  $services = MediaWikiServices::getInstance();
558  foreach ( $targets as $target ) {
559  if ( !$target instanceof LinkTarget ) {
560  try {
561  $target = $this->titleParser->parseTitle( $target, NS_MAIN );
562  }
563  catch ( MalformedTitleException $e ) {
564  continue;
565  }
566  }
567 
568  $ns = $target->getNamespace();
569  $dbKey = $target->getDBkey();
570  $expandedTargets[] =
571  new TitleValue( $services->getNamespaceInfo()->getSubject( $ns ), $dbKey );
572  $expandedTargets[] =
573  new TitleValue( $services->getNamespaceInfo()->getTalk( $ns ), $dbKey );
574  }
575  return $expandedTargets;
576  }
577 
578  public function submitNormal( $data ) {
579  $removed = [];
580 
581  foreach ( $data as $titles ) {
582  $this->unwatchTitles( $titles );
583  $removed = array_merge( $removed, $titles );
584  }
585 
586  if ( count( $removed ) > 0 ) {
587  $this->successMessage = $this->msg( 'watchlistedit-normal-done'
588  )->numParams( count( $removed ) )->parse();
589  $this->showTitles( $removed, $this->successMessage );
590 
591  return true;
592  } else {
593  return false;
594  }
595  }
596 
602  protected function getNormalForm() {
603  $fields = [];
604  $count = 0;
605 
606  // Allow subscribers to manipulate the list of watched pages (or use it
607  // to preload lots of details at once)
608  $watchlistInfo = $this->getWatchlistInfo();
609  $this->getHookRunner()->onWatchlistEditorBeforeFormRender( $watchlistInfo );
610 
611  foreach ( $watchlistInfo as $namespace => $pages ) {
612  $options = [];
613 
614  foreach ( array_keys( $pages ) as $dbkey ) {
615  $title = Title::makeTitleSafe( $namespace, $dbkey );
616 
617  if ( $this->checkTitle( $title, $namespace, $dbkey ) ) {
618  $text = $this->buildRemoveLine( $title );
619  $options[$text] = $title->getPrefixedText();
620  $count++;
621  }
622  }
623 
624  // checkTitle can filter some options out, avoid empty sections
625  if ( count( $options ) > 0 ) {
626  $fields['TitlesNs' . $namespace] = [
627  'class' => EditWatchlistCheckboxSeriesField::class,
628  'options' => $options,
629  'section' => "ns$namespace",
630  ];
631  }
632  }
633  $this->cleanupWatchlist();
634 
635  if ( count( $fields ) > 1 && $count > 30 ) {
636  $this->toc = Linker::tocIndent();
637  $tocLength = 0;
638  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
639 
640  foreach ( $fields as $data ) {
641  # strip out the 'ns' prefix from the section name:
642  $ns = substr( $data['section'], 2 );
643 
644  $nsText = ( $ns == NS_MAIN )
645  ? $this->msg( 'blanknamespace' )->escaped()
646  : htmlspecialchars( $contLang->getFormattedNsText( $ns ) );
647  $this->toc .= Linker::tocLine( "editwatchlist-{$data['section']}", $nsText,
648  $this->getLanguage()->formatNum( ++$tocLength ), 1 ) . Linker::tocLineEnd();
649  }
650 
651  $this->toc = Linker::tocList( $this->toc );
652  } else {
653  $this->toc = false;
654  }
655 
656  $context = new DerivativeContext( $this->getContext() );
657  $context->setTitle( $this->getPageTitle() ); // Remove subpage
658  $form = new EditWatchlistNormalHTMLForm( $fields, $context );
659  $form->setSubmitTextMsg( 'watchlistedit-normal-submit' );
660  $form->setSubmitDestructive();
661  # Used message keys:
662  # 'accesskey-watchlistedit-normal-submit', 'tooltip-watchlistedit-normal-submit'
663  $form->setSubmitTooltip( 'watchlistedit-normal-submit' );
664  $form->setWrapperLegendMsg( 'watchlistedit-normal-legend' );
665  $form->addHeaderText( $this->msg( 'watchlistedit-normal-explain' )->parse() );
666  $form->setSubmitCallback( [ $this, 'submitNormal' ] );
667 
668  return $form;
669  }
670 
677  private function buildRemoveLine( $title ) {
678  $linkRenderer = $this->getLinkRenderer();
679  $link = $linkRenderer->makeLink( $title );
680 
681  $tools = [];
682  $tools['talk'] = $linkRenderer->makeLink(
683  $title->getTalkPage(),
684  $this->msg( 'talkpagelinktext' )->text()
685  );
686 
687  if ( $title->exists() ) {
688  $tools['history'] = $linkRenderer->makeKnownLink(
689  $title,
690  $this->msg( 'history_small' )->text(),
691  [],
692  [ 'action' => 'history' ]
693  );
694  }
695 
696  if ( $title->getNamespace() == NS_USER && !$title->isSubpage() ) {
697  $tools['contributions'] = $linkRenderer->makeKnownLink(
698  SpecialPage::getTitleFor( 'Contributions', $title->getText() ),
699  $this->msg( 'contribslink' )->text()
700  );
701  }
702 
703  $this->getHookRunner()->onWatchlistEditorBuildRemoveLine(
704  $tools, $title, $title->isRedirect(), $this->getSkin(), $link );
705 
706  if ( $title->isRedirect() ) {
707  // Linker already makes class mw-redirect, so this is redundant
708  $link = '<span class="watchlistredir">' . $link . '</span>';
709  }
710 
711  return $link . ' ' .
712  $this->msg( 'parentheses' )->rawParams( $this->getLanguage()->pipeList( $tools ) )->escaped();
713  }
714 
720  protected function getRawForm() {
721  $titles = implode( "\n", $this->getWatchlist() );
722  $fields = [
723  'Titles' => [
724  'type' => 'textarea',
725  'label-message' => 'watchlistedit-raw-titles',
726  'default' => $titles,
727  ],
728  ];
729  $context = new DerivativeContext( $this->getContext() );
730  $context->setTitle( $this->getPageTitle( 'raw' ) ); // Reset subpage
731  $form = new OOUIHTMLForm( $fields, $context );
732  $form->setSubmitTextMsg( 'watchlistedit-raw-submit' );
733  # Used message keys: 'accesskey-watchlistedit-raw-submit', 'tooltip-watchlistedit-raw-submit'
734  $form->setSubmitTooltip( 'watchlistedit-raw-submit' );
735  $form->setWrapperLegendMsg( 'watchlistedit-raw-legend' );
736  $form->addHeaderText( $this->msg( 'watchlistedit-raw-explain' )->parse() );
737  $form->setSubmitCallback( [ $this, 'submitRaw' ] );
738 
739  return $form;
740  }
741 
747  protected function getClearForm() {
748  $context = new DerivativeContext( $this->getContext() );
749  $context->setTitle( $this->getPageTitle( 'clear' ) ); // Reset subpage
750  $form = new OOUIHTMLForm( [], $context );
751  $form->setSubmitTextMsg( 'watchlistedit-clear-submit' );
752  # Used message keys: 'accesskey-watchlistedit-clear-submit', 'tooltip-watchlistedit-clear-submit'
753  $form->setSubmitTooltip( 'watchlistedit-clear-submit' );
754  $form->setWrapperLegendMsg( 'watchlistedit-clear-legend' );
755  $form->addHeaderText( $this->msg( 'watchlistedit-clear-explain' )->parse() );
756  $form->setSubmitCallback( [ $this, 'submitClear' ] );
757  $form->setSubmitDestructive();
758 
759  return $form;
760  }
761 
770  public static function getMode( $request, $par ) {
771  $mode = strtolower( $request->getVal( 'action', $par ) );
772 
773  switch ( $mode ) {
774  case 'clear':
775  case self::EDIT_CLEAR:
776  return self::EDIT_CLEAR;
777  case 'raw':
778  case self::EDIT_RAW:
779  return self::EDIT_RAW;
780  case 'edit':
781  case self::EDIT_NORMAL:
782  return self::EDIT_NORMAL;
783  default:
784  return false;
785  }
786  }
787 
796  public static function buildTools( $lang, LinkRenderer $linkRenderer = null ) {
797  if ( !$lang instanceof Language ) {
798  // back-compat where the first parameter was $unused
799  global $wgLang;
800  $lang = $wgLang;
801  }
802  if ( !$linkRenderer ) {
803  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
804  }
805 
806  $tools = [];
807  $modes = [
808  'view' => [ 'Watchlist', false ],
809  'edit' => [ 'EditWatchlist', false ],
810  'raw' => [ 'EditWatchlist', 'raw' ],
811  'clear' => [ 'EditWatchlist', 'clear' ],
812  ];
813 
814  foreach ( $modes as $mode => $arr ) {
815  // can use messages 'watchlisttools-view', 'watchlisttools-edit', 'watchlisttools-raw'
816  $tools[] = $linkRenderer->makeKnownLink(
817  SpecialPage::getTitleFor( $arr[0], $arr[1] ),
818  wfMessage( "watchlisttools-{$mode}" )->text()
819  );
820  }
821 
822  return Html::rawElement(
823  'span',
824  [ 'class' => 'mw-watchlist-toollinks' ],
825  wfMessage( 'parentheses' )->rawParams( $lang->pipeList( $tools ) )->escaped()
826  );
827  }
828 }
SpecialPage\getPageTitle
getPageTitle( $subpage=false)
Get a self-referential title object.
Definition: SpecialPage.php:669
SpecialEditWatchlist\submitNormal
submitNormal( $data)
Definition: SpecialEditWatchlist.php:578
SpecialEditWatchlist\EDIT_CLEAR
const EDIT_CLEAR
Editing modes.
Definition: SpecialEditWatchlist.php:46
SpecialEditWatchlist\unwatchTitles
unwatchTitles(array $targets)
Remove a list of titles from a user's watchlist.
Definition: SpecialEditWatchlist.php:521
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:374
SpecialEditWatchlist\$watchedItemStore
WatchedItemStoreInterface $watchedItemStore
Definition: SpecialEditWatchlist.php:64
SpecialPage\msg
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:800
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:332
SpecialEditWatchlist\EDIT_RAW
const EDIT_RAW
Definition: SpecialEditWatchlist.php:47
SpecialEditWatchlist\checkTitle
checkTitle( $title, $namespace, $dbKey)
Validates watchlist entry.
Definition: SpecialEditWatchlist.php:447
SpecialEditWatchlist\initServices
initServices()
Initialize any services we'll need (unless it has already been provided via a setter).
Definition: SpecialEditWatchlist.php:75
LinkBatch
Class representing a list of titles The execute() method checks them all for existence and adds them ...
Definition: LinkBatch.php:35
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:716
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:146
$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:29
Linker\tocIndent
static tocIndent()
Add another level to the Table of Contents.
Definition: Linker.php:1666
MediaWiki\Linker\LinkRenderer
Class that generates HTML links for pages.
Definition: LinkRenderer.php:43
SpecialEditWatchlist\submitRaw
submitRaw( $data)
Definition: SpecialEditWatchlist.php:223
SpecialPage\checkPermissions
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
Definition: SpecialPage.php:328
SpecialEditWatchlist\buildRemoveLine
buildRemoveLine( $title)
Build the label for a checkbox, with a link to the title, and various additional bits.
Definition: SpecialEditWatchlist.php:677
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1198
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:90
SpecialEditWatchlist\watchTitles
watchTitles(array $targets)
Add a list of targets to a user's watchlist.
Definition: SpecialEditWatchlist.php:503
SpecialEditWatchlist\getExpandedTargets
getExpandedTargets(array $targets)
Definition: SpecialEditWatchlist.php:555
SpecialPage\getLanguage
getLanguage()
Shortcut to get user's language.
Definition: SpecialPage.php:746
SpecialPage\getName
getName()
Get the name of this Special Page.
Definition: SpecialPage.php:160
Linker\tocLine
static tocLine( $anchor, $tocline, $tocnumber, $level, $sectionIndex=false)
parameter level defines if we are on an indentation level
Definition: Linker.php:1692
SpecialEditWatchlist\$badItems
$badItems
Definition: SpecialEditWatchlist.php:54
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:1728
SpecialEditWatchlist\clearUserWatchedItemsNow
clearUserWatchedItemsNow(string $messageFor)
You should call clearUserWatchedItems() instead to decide if this should use the JobQueue.
Definition: SpecialEditWatchlist.php:294
SpecialEditWatchlist\$titleParser
TitleParser $titleParser
Definition: SpecialEditWatchlist.php:59
SpecialEditWatchlist\runWatchUnwatchCompleteHook
runWatchUnwatchCompleteHook( $action, $targets)
Definition: SpecialEditWatchlist.php:535
SpecialEditWatchlist\clearUserWatchedItemsUsingJobQueue
clearUserWatchedItemsUsingJobQueue()
You should call clearUserWatchedItems() instead to decide if this should use the JobQueue.
Definition: SpecialEditWatchlist.php:311
OOUIHTMLForm
Compact stacked vertical format for forms, implemented using OOUI widgets.
Definition: OOUIHTMLForm.php:27
SpecialEditWatchlist\execute
execute( $mode)
Main execution point.
Definition: SpecialEditWatchlist.php:90
NS_MAIN
const NS_MAIN
Definition: Defines.php:69
EditWatchlistNormalHTMLForm
Extend OOUIHTMLForm purely so we can have a more sane 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:30
SpecialEditWatchlist\EDIT_NORMAL
const EDIT_NORMAL
Definition: SpecialEditWatchlist.php:48
SpecialPage\getHookRunner
getHookRunner()
Definition: SpecialPage.php:974
WikiPage\factory
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:146
SpecialEditWatchlist\__construct
__construct(WatchedItemStoreInterface $watchedItemStore)
Definition: SpecialEditWatchlist.php:66
SpecialEditWatchlist\getRawForm
getRawForm()
Get a form for editing the watchlist in "raw" mode.
Definition: SpecialEditWatchlist.php:720
SpecialEditWatchlist\executeViewEditWatchlist
executeViewEditWatchlist()
Executes an edit mode for the watchlist view, from which you can manage your watchlist.
Definition: SpecialEditWatchlist.php:159
SpecialEditWatchlist\extractTitles
extractTitles( $list)
Extract a list of titles from a blob of text, returning (prefixed) strings; unwatchable titles are ig...
Definition: SpecialEditWatchlist.php:194
$wgLang
$wgLang
Definition: Setup.php:781
Linker\tocLineEnd
static tocLineEnd()
End a Table Of Contents line.
Definition: Linker.php:1716
$args
if( $line===false) $args
Definition: mcc.php:124
SpecialEditWatchlist
Provides the UI through which users can perform editing operations on their watchlist.
Definition: SpecialEditWatchlist.php:41
$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:551
SpecialPage\getUser
getUser()
Shortcut to get the User executing this instance.
Definition: SpecialPage.php:726
SpecialEditWatchlist\showTitles
showTitles( $titles, &$output)
Print out a list of linked titles.
Definition: SpecialEditWatchlist.php:325
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:595
TitleParser
A title parser service for MediaWiki.
Definition: TitleParser.php:33
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:913
SpecialPage\getContext
getContext()
Gets the context this SpecialPage is executed in.
Definition: SpecialPage.php:689
SpecialPage\requireLogin
requireLogin( $reasonMsg='exception-nologin-text', $titleMsg='exception-nologin')
If the user is not logged in, throws UserNotLoggedIn error.
Definition: SpecialPage.php:358
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:621
SpecialEditWatchlist\getMode
static getMode( $request, $par)
Determine whether we are editing the watchlist, and if so, what kind of editing operation.
Definition: SpecialEditWatchlist.php:770
SpecialEditWatchlist\getSubpagesForPrefixSearch
getSubpagesForPrefixSearch()
Return an array of subpages that this special page will accept.
Definition: SpecialEditWatchlist.php:178
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:706
SpecialEditWatchlist\cleanupWatchlist
cleanupWatchlist()
Attempts to clean up broken items.
Definition: SpecialEditWatchlist.php:469
SpecialEditWatchlist\doesWrites
doesWrites()
Indicates whether this special page may perform database writes.
Definition: SpecialEditWatchlist.php:81
WatchedItemStoreInterface\SORT_ASC
const SORT_ASC
Definition: WatchedItemStoreInterface.php:35
$context
$context
Definition: load.php:43
SpecialEditWatchlist\outputSubtitle
outputSubtitle()
Renders a subheader on the watchlist page.
Definition: SpecialEditWatchlist.php:144
SpecialEditWatchlist\$toc
$toc
Definition: SpecialEditWatchlist.php:52
SpecialPage\getLinkRenderer
getLinkRenderer()
Definition: SpecialPage.php:912
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:796
Title
Represents a title within MediaWiki.
Definition: Title.php:42
SpecialEditWatchlist\getClearForm
getClearForm()
Get a form for clearing the watchlist.
Definition: SpecialEditWatchlist.php:747
MalformedTitleException
MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
Definition: MalformedTitleException.php:25
SpecialEditWatchlist\clearUserWatchedItems
clearUserWatchedItems(string $messageFor)
Makes a decision about using the JobQueue or not for clearing a users watchlist.
Definition: SpecialEditWatchlist.php:281
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:209
NS_USER
const NS_USER
Definition: Defines.php:71
SpecialEditWatchlist\getNormalForm
getNormalForm()
Get the standard watchlist editing form.
Definition: SpecialEditWatchlist.php:602
SpecialPage\checkReadOnly
checkReadOnly()
If the wiki is currently in readonly mode, throws a ReadOnlyError.
Definition: SpecialPage.php:341
SpecialPage\$linkRenderer
MediaWiki Linker LinkRenderer null $linkRenderer
Definition: SpecialPage.php:69
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:415
WatchedItemStoreInterface
Definition: WatchedItemStoreInterface.php:30
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:55
DeferredUpdates\addCallableUpdate
static addCallableUpdate( $callable, $stage=self::POSTSEND, $dbw=null)
Add a callable update.
Definition: DeferredUpdates.php:145
SpecialEditWatchlist\submitClear
submitClear( $data)
Handler for the clear form submission.
Definition: SpecialEditWatchlist.php:270
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:636
Language
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:41
SpecialEditWatchlist\$successMessage
$successMessage
Definition: SpecialEditWatchlist.php:50
TitleValue
Represents a page (or page fragment) title within MediaWiki.
Definition: TitleValue.php:37
Title\newFromTitleValue
static newFromTitleValue(TitleValue $titleValue, $forceClone='')
Returns a Title given a TitleValue.
Definition: Title.php:269