From c1f9b1f7b1b77776192048005dcc66dcf3df2bfb Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Sat, 27 Dec 2014 15:41:37 +0100 Subject: Update to MediaWiki 1.24.1 --- includes/specials/SpecialEditWatchlist.php | 222 +++++++++++++++++++---------- 1 file changed, 150 insertions(+), 72 deletions(-) (limited to 'includes/specials/SpecialEditWatchlist.php') diff --git a/includes/specials/SpecialEditWatchlist.php b/includes/specials/SpecialEditWatchlist.php index 501552e9..3656b9cc 100644 --- a/includes/specials/SpecialEditWatchlist.php +++ b/includes/specials/SpecialEditWatchlist.php @@ -36,7 +36,8 @@ */ class SpecialEditWatchlist extends UnlistedSpecialPage { /** - * Editing modes + * Editing modes. EDIT_CLEAR is no longer used; the "Clear" link scared people + * too much. Now it's passed on to the raw editor, from which it's very easy to clear. */ const EDIT_CLEAR = 1; const EDIT_RAW = 2; @@ -55,34 +56,21 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { /** * Main execution point * - * @param $mode int + * @param int $mode */ public function execute( $mode ) { $this->setHeaders(); - $out = $this->getOutput(); - # Anons don't get a watchlist - if ( $this->getUser()->isAnon() ) { - $out->setPageTitle( $this->msg( 'watchnologin' ) ); - $llink = Linker::linkKnown( - SpecialPage::getTitleFor( 'Userlogin' ), - $this->msg( 'loginreqlink' )->escaped(), - array(), - array( 'returnto' => $this->getTitle()->getPrefixedText() ) - ); - $out->addHTML( $this->msg( 'watchlistanontext' )->rawParams( $llink )->parse() ); + $this->requireLogin( 'watchlistanontext' ); - return; - } + $out = $this->getOutput(); $this->checkPermissions(); $this->checkReadOnly(); $this->outputHeader(); - - $out->addSubtitle( $this->msg( 'watchlistfor2', $this->getUser()->getName() ) - ->rawParams( SpecialEditWatchlist::buildTools( null ) ) ); + $this->outputSubtitle(); # B/C: $mode used to be waaay down the parameter list, and the first parameter # was $wgUser @@ -95,10 +83,6 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { $mode = self::getMode( $this->getRequest(), $mode ); switch ( $mode ) { - case self::EDIT_CLEAR: - // The "Clear" link scared people too much. - // Pass on to the raw editor, from which it's very easy to clear. - case self::EDIT_RAW: $out->setPageTitle( $this->msg( 'watchlistedit-raw-title' ) ); $form = $this->getRawForm(); @@ -107,26 +91,73 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) ); } break; - - case self::EDIT_NORMAL: - default: - $out->setPageTitle( $this->msg( 'watchlistedit-normal-title' ) ); - $form = $this->getNormalForm(); + case self::EDIT_CLEAR: + $out->setPageTitle( $this->msg( 'watchlistedit-clear-title' ) ); + $form = $this->getClearForm(); if ( $form->show() ) { $out->addHTML( $this->successMessage ); $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) ); - } elseif ( $this->toc !== false ) { - $out->prependHTML( $this->toc ); } break; + + case self::EDIT_NORMAL: + default: + $this->executeViewEditWatchlist(); + break; + } + } + + /** + * Renders a subheader on the watchlist page. + */ + protected function outputSubtitle() { + $out = $this->getOutput(); + $out->addSubtitle( $this->msg( 'watchlistfor2', $this->getUser()->getName() ) + ->rawParams( SpecialEditWatchlist::buildTools( null ) ) ); + } + + /** + * Executes an edit mode for the watchlist view, from which you can manage your watchlist + * + */ + protected function executeViewEditWatchlist() { + $out = $this->getOutput(); + $out->setPageTitle( $this->msg( 'watchlistedit-normal-title' ) ); + $form = $this->getNormalForm(); + if ( $form->show() ) { + $out->addHTML( $this->successMessage ); + $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) ); + } elseif ( $this->toc !== false ) { + $out->prependHTML( $this->toc ); + $out->addModules( 'mediawiki.toc' ); } } + /** + * Return an array of subpages beginning with $search that this special page will accept. + * + * @param string $search Prefix to search for + * @param int $limit Maximum number of results to return + * @return string[] Matching subpages + */ + public function prefixSearchSubpages( $search, $limit = 10 ) { + return self::prefixSearchArray( + $search, + $limit, + // SpecialWatchlist uses SpecialEditWatchlist::getMode, so new types should be added + // here and there - no 'edit' here, because that the default for this page + array( + 'clear', + 'raw', + ) + ); + } + /** * Extract a list of titles from a blob of text, returning * (prefixed) strings; unwatchable titles are ignored * - * @param $list String + * @param string $list * @return array */ private function extractTitles( $list ) { @@ -176,14 +207,14 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { } if ( count( $toWatch ) > 0 ) { - $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-added' - )->numParams( count( $toWatch ) )->parse(); + $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-added' ) + ->numParams( count( $toWatch ) )->parse(); $this->showTitles( $toWatch, $this->successMessage ); } if ( count( $toUnwatch ) > 0 ) { - $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-removed' - )->numParams( count( $toUnwatch ) )->parse(); + $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-removed' ) + ->numParams( count( $toUnwatch ) )->parse(); $this->showTitles( $toUnwatch, $this->successMessage ); } } else { @@ -204,19 +235,35 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { return true; } + public function submitClear( $data ) { + $current = $this->getWatchlist(); + $this->clearWatchlist(); + $this->getUser()->invalidateCache(); + $this->successMessage = $this->msg( 'watchlistedit-clear-done' )->parse(); + $this->successMessage .= ' ' . $this->msg( 'watchlistedit-clear-removed' ) + ->numParams( count( $current ) )->parse(); + $this->showTitles( $current, $this->successMessage ); + + return true; + } + /** * Print out a list of linked titles * * $titles can be an array of strings or Title objects; the former * is preferred, since Titles are very memory-heavy * - * @param array $titles of strings, or Title objects - * @param $output String + * @param array $titles Array of strings, or Title objects + * @param string $output */ private function showTitles( $titles, &$output ) { $talk = $this->msg( 'talkpagelinktext' )->escaped(); // Do a batch existence check $batch = new LinkBatch(); + if ( count( $titles ) >= 100 ) { + $output = wfMessage( 'watchlistedit-too-many' )->parse(); + return; + } foreach ( $titles as $title ) { if ( !$title instanceof Title ) { $title = Title::newFromText( $title ); @@ -300,7 +347,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { * * @return array */ - private function getWatchlistInfo() { + protected function getWatchlistInfo() { $titles = array(); $dbr = wfGetDB( DB_MASTER ); @@ -332,7 +379,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { * @param Title $title * @param int $namespace * @param string $dbKey - * @return bool: Whether this item is valid + * @return bool Whether this item is valid */ private function checkTitle( $title, $namespace, $dbKey ) { if ( $title @@ -403,7 +450,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { * $titles can be an array of strings or Title objects; the former * is preferred, since Titles are very memory-heavy * - * @param array $titles of strings, or Title objects + * @param array $titles Array of strings, or Title objects */ private function watchTitles( $titles ) { $dbw = wfGetDB( DB_MASTER ); @@ -439,7 +486,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { * $titles can be an array of strings or Title objects; the former * is preferred, since Titles are very memory-heavy * - * @param array $titles of strings, or Title objects + * @param array $titles Array of strings, or Title objects */ private function unwatchTitles( $titles ) { $dbw = wfGetDB( DB_MASTER ); @@ -506,24 +553,35 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { $fields = array(); $count = 0; - foreach ( $this->getWatchlistInfo() as $namespace => $pages ) { - if ( $namespace >= 0 ) { - $fields['TitlesNs' . $namespace] = array( - 'class' => 'EditWatchlistCheckboxSeriesField', - 'options' => array(), - 'section' => "ns$namespace", - ); - } + // Allow subscribers to manipulate the list of watched pages (or use it + // to preload lots of details at once) + $watchlistInfo = $this->getWatchlistInfo(); + wfRunHooks( + 'WatchlistEditorBeforeFormRender', + array( &$watchlistInfo ) + ); + + foreach ( $watchlistInfo as $namespace => $pages ) { + $options = array(); foreach ( array_keys( $pages ) as $dbkey ) { $title = Title::makeTitleSafe( $namespace, $dbkey ); if ( $this->checkTitle( $title, $namespace, $dbkey ) ) { $text = $this->buildRemoveLine( $title ); - $fields['TitlesNs' . $namespace]['options'][$text] = $title->getPrefixedText(); + $options[$text] = $title->getPrefixedText(); $count++; } } + + // checkTitle can filter some options out, avoid empty sections + if ( count( $options ) > 0 ) { + $fields['TitlesNs' . $namespace] = array( + 'class' => 'EditWatchlistCheckboxSeriesField', + 'options' => $options, + 'section' => "ns$namespace", + ); + } } $this->cleanupWatchlist(); @@ -548,10 +606,11 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { } $context = new DerivativeContext( $this->getContext() ); - $context->setTitle( $this->getTitle() ); // Remove subpage + $context->setTitle( $this->getPageTitle() ); // Remove subpage $form = new EditWatchlistNormalHTMLForm( $fields, $context ); $form->setSubmitTextMsg( 'watchlistedit-normal-submit' ); - # Used message keys: 'accesskey-watchlistedit-normal-submit', 'tooltip-watchlistedit-normal-submit' + # Used message keys: + # 'accesskey-watchlistedit-normal-submit', 'tooltip-watchlistedit-normal-submit' $form->setSubmitTooltip( 'watchlistedit-normal-submit' ); $form->setWrapperLegendMsg( 'watchlistedit-normal-legend' ); $form->addHeaderText( $this->msg( 'watchlistedit-normal-explain' )->parse() ); @@ -563,21 +622,16 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { /** * Build the label for a checkbox, with a link to the title, and various additional bits * - * @param $title Title + * @param Title $title * @return string */ private function buildRemoveLine( $title ) { $link = Linker::link( $title ); - if ( $title->isRedirect() ) { - // Linker already makes class mw-redirect, so this is redundant - $link = '' . $link . ''; - } - - $tools[] = Linker::link( $title->getTalkPage(), $this->msg( 'talkpagelinktext' )->escaped() ); + $tools['talk'] = Linker::link( $title->getTalkPage(), $this->msg( 'talkpagelinktext' )->escaped() ); if ( $title->exists() ) { - $tools[] = Linker::linkKnown( + $tools['history'] = Linker::linkKnown( $title, $this->msg( 'history_short' )->escaped(), array(), @@ -586,13 +640,21 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { } if ( $title->getNamespace() == NS_USER && !$title->isSubpage() ) { - $tools[] = Linker::linkKnown( + $tools['contributions'] = Linker::linkKnown( SpecialPage::getTitleFor( 'Contributions', $title->getText() ), $this->msg( 'contributions' )->escaped() ); } - wfRunHooks( 'WatchlistEditorBuildRemoveLine', array( &$tools, $title, $title->isRedirect(), $this->getSkin() ) ); + wfRunHooks( + 'WatchlistEditorBuildRemoveLine', + array( &$tools, $title, $title->isRedirect(), $this->getSkin(), &$link ) + ); + + if ( $title->isRedirect() ) { + // Linker already makes class mw-redirect, so this is redundant + $link = '' . $link . ''; + } return $link . " (" . $this->getLanguage()->pipeList( $tools ) . ")"; } @@ -612,7 +674,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { ), ); $context = new DerivativeContext( $this->getContext() ); - $context->setTitle( $this->getTitle( 'raw' ) ); // Reset subpage + $context->setTitle( $this->getPageTitle( 'raw' ) ); // Reset subpage $form = new HTMLForm( $fields, $context ); $form->setSubmitTextMsg( 'watchlistedit-raw-submit' ); # Used message keys: 'accesskey-watchlistedit-raw-submit', 'tooltip-watchlistedit-raw-submit' @@ -624,12 +686,31 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { return $form; } + /** + * Get a form for clearing the watchlist + * + * @return HTMLForm + */ + protected function getClearForm() { + $context = new DerivativeContext( $this->getContext() ); + $context->setTitle( $this->getPageTitle( 'clear' ) ); // Reset subpage + $form = new HTMLForm( array(), $context ); + $form->setSubmitTextMsg( 'watchlistedit-clear-submit' ); + # Used message keys: 'accesskey-watchlistedit-clear-submit', 'tooltip-watchlistedit-clear-submit' + $form->setSubmitTooltip( 'watchlistedit-clear-submit' ); + $form->setWrapperLegendMsg( 'watchlistedit-clear-legend' ); + $form->addHeaderText( $this->msg( 'watchlistedit-clear-explain' )->parse() ); + $form->setSubmitCallback( array( $this, 'submitClear' ) ); + + return $form; + } + /** * Determine whether we are editing the watchlist, and if so, what * kind of editing operation * - * @param $request WebRequest - * @param $par mixed + * @param WebRequest $request + * @param string $par * @return int */ public static function getMode( $request, $par ) { @@ -654,7 +735,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { * Build a set of links for convenient navigation * between watchlist viewing and editing modes * - * @param $unused + * @param null $unused * @return string */ public static function buildTools( $unused ) { @@ -665,6 +746,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { 'view' => array( 'Watchlist', false ), 'edit' => array( 'EditWatchlist', false ), 'raw' => array( 'EditWatchlist', 'raw' ), + 'clear' => array( 'EditWatchlist', 'clear' ), ); foreach ( $modes as $mode => $arr ) { @@ -683,10 +765,6 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { } } -# B/C since 1.18 -class WatchlistEditor extends SpecialEditWatchlist { -} - /** * Extend HTMLForm purely so we can have a more sane way of getting the section headers */ @@ -712,9 +790,9 @@ class EditWatchlistCheckboxSeriesField extends HTMLMultiSelectField { * form is open (bug 32126), but we know that invalid items will * be harmless so we can override it here. * - * @param string $value the value the field was submitted with - * @param array $alldata the data collected from the form - * @return Mixed Bool true on success, or String error to display. + * @param string $value The value the field was submitted with + * @param array $alldata The data collected from the form + * @return bool|string Bool true on success, or String error to display. */ function validate( $value, $alldata ) { // Need to call into grandparent to be a good citizen. :) -- cgit v1.2.3-54-g00ecf