r85960 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r85959‎ | r85960 | r85961 >
Date:17:25, 13 April 2011
Author:aaron
Status:ok
Tags:
Comment:
* Split off UI hooks into FlaggedRevsUIHooks class
* Renamed RejectConfirmationFormGUI -> RejectConfirmationFormUI and RevisionReviewFormGUI -> RevisionReviewFormUI...the "G" is overkill ;)
Modified paths:
  • /trunk/extensions/FlaggedRevs/FlaggedRevs.hooks.php (modified) (history)
  • /trunk/extensions/FlaggedRevs/FlaggedRevs.php (modified) (history)
  • /trunk/extensions/FlaggedRevs/presentation/FlaggedPageView.php (modified) (history)
  • /trunk/extensions/FlaggedRevs/presentation/FlaggedRevsUI.hooks.php (added) (history)
  • /trunk/extensions/FlaggedRevs/presentation/RejectConfirmationFormGUI.php (deleted) (history)
  • /trunk/extensions/FlaggedRevs/presentation/RejectConfirmationFormUI.php (added) (history)
  • /trunk/extensions/FlaggedRevs/presentation/RevisionReviewFormGUI.php (deleted) (history)
  • /trunk/extensions/FlaggedRevs/presentation/RevisionReviewFormUI.php (added) (history)
  • /trunk/extensions/FlaggedRevs/presentation/specialpages/actions/RevisionReview_body.php (modified) (history)

Diff [purge]

Index: trunk/extensions/FlaggedRevs/FlaggedRevs.php
@@ -249,6 +249,7 @@
250250
251251 # Event handler classes...
252252 $wgAutoloadClasses['FlaggedRevsHooks'] = $dir . 'FlaggedRevs.hooks.php';
 253+$wgAutoloadClasses['FlaggedRevsUIHooks'] = $dir . 'presentation/FlaggedRevsUI.hooks.php';
253254 $wgAutoloadClasses['FlaggedRevsApiHooks'] = $dir . 'api/FlaggedRevsApi.hooks.php';
254255 $wgAutoloadClasses['FlaggedRevsUpdaterHooks'] = $dir . 'updater/FlaggedRevsUpdater.hooks.php';
255256
@@ -272,8 +273,8 @@
273274 $wgAutoloadClasses['FlaggedPageView'] = $dir . 'presentation/FlaggedPageView.php';
274275 $wgAutoloadClasses['FlaggedRevsLogView'] = $dir . 'presentation/FlaggedRevsLogView.php';
275276 $wgAutoloadClasses['FlaggedRevsXML'] = $dir . 'presentation/FlaggedRevsXML.php';
276 -$wgAutoloadClasses['RevisionReviewFormGUI'] = $dir . 'presentation/RevisionReviewFormGUI.php';
277 -$wgAutoloadClasses['RejectConfirmationFormGUI'] = $dir . 'presentation/RejectConfirmationFormGUI.php';
 277+$wgAutoloadClasses['RevisionReviewFormUI'] = $dir . 'presentation/RevisionReviewFormUI.php';
 278+$wgAutoloadClasses['RejectConfirmationFormUI'] = $dir . 'presentation/RejectConfirmationFormUI.php';
278279
279280 $specialActionDir = $dir . 'presentation/specialpages/actions/';
280281 # Load revision review UI
@@ -393,52 +394,52 @@
394395
395396 # ######## User interface #########
396397 # Override current revision, add patrol links, set cache...
397 -$wgHooks['ArticleViewHeader'][] = 'FlaggedRevsHooks::onArticleViewHeader';
398 -$wgHooks['ImagePageFindFile'][] = 'FlaggedRevsHooks::onImagePageFindFile';
 398+$wgHooks['ArticleViewHeader'][] = 'FlaggedRevsUIHooks::onArticleViewHeader';
 399+$wgHooks['ImagePageFindFile'][] = 'FlaggedRevsUIHooks::onImagePageFindFile';
399400 # Override redirect behavior...
400 -$wgHooks['InitializeArticleMaybeRedirect'][] = 'FlaggedRevsHooks::overrideRedirect';
 401+$wgHooks['InitializeArticleMaybeRedirect'][] = 'FlaggedRevsUIHooks::overrideRedirect';
401402 # Set page view tabs
402 -$wgHooks['SkinTemplateTabs'][] = 'FlaggedRevsHooks::onSkinTemplateTabs'; // All skins
403 -$wgHooks['SkinTemplateNavigation'][] = 'FlaggedRevsHooks::onSkinTemplateNavigation'; // Vector
 403+$wgHooks['SkinTemplateTabs'][] = 'FlaggedRevsUIHooks::onSkinTemplateTabs'; // All skins
 404+$wgHooks['SkinTemplateNavigation'][] = 'FlaggedRevsUIHooks::onSkinTemplateNavigation'; // Vector
404405 # Add notice tags to edit view
405 -$wgHooks['EditPage::showEditForm:initial'][] = 'FlaggedRevsHooks::addToEditView';
 406+$wgHooks['EditPage::showEditForm:initial'][] = 'FlaggedRevsUIHooks::addToEditView';
406407 # Tweak submit button name/title
407 -$wgHooks['EditPageBeforeEditButtons'][] = 'FlaggedRevsHooks::onBeforeEditButtons';
 408+$wgHooks['EditPageBeforeEditButtons'][] = 'FlaggedRevsUIHooks::onBeforeEditButtons';
408409 # Autoreview information from form
409 -$wgHooks['EditPageBeforeEditChecks'][] = 'FlaggedRevsHooks::addReviewCheck';
410 -$wgHooks['EditPage::showEditForm:fields'][] = 'FlaggedRevsHooks::addRevisionIDField';
 410+$wgHooks['EditPageBeforeEditChecks'][] = 'FlaggedRevsUIHooks::addReviewCheck';
 411+$wgHooks['EditPage::showEditForm:fields'][] = 'FlaggedRevsUIHooks::addRevisionIDField';
411412 # Add draft link to section edit error
412 -$wgHooks['EditPageNoSuchSection'][] = 'FlaggedRevsHooks::onNoSuchSection';
 413+$wgHooks['EditPageNoSuchSection'][] = 'FlaggedRevsUIHooks::onNoSuchSection';
413414 # Add notice tags to history
414 -$wgHooks['PageHistoryBeforeList'][] = 'FlaggedRevsHooks::addToHistView';
 415+$wgHooks['PageHistoryBeforeList'][] = 'FlaggedRevsUIHooks::addToHistView';
415416 # Add review form and visiblity settings link
416 -$wgHooks['SkinAfterContent'][] = 'FlaggedRevsHooks::onSkinAfterContent';
 417+$wgHooks['SkinAfterContent'][] = 'FlaggedRevsUIHooks::onSkinAfterContent';
417418 # Mark items in page history
418 -$wgHooks['PageHistoryPager::getQueryInfo'][] = 'FlaggedRevsHooks::addToHistQuery';
419 -$wgHooks['PageHistoryLineEnding'][] = 'FlaggedRevsHooks::addToHistLine';
420 -$wgHooks['LocalFile::getHistory'][] = 'FlaggedRevsHooks::addToFileHistQuery';
421 -$wgHooks['ImagePageFileHistoryLine'][] = 'FlaggedRevsHooks::addToFileHistLine';
 419+$wgHooks['PageHistoryPager::getQueryInfo'][] = 'FlaggedRevsUIHooks::addToHistQuery';
 420+$wgHooks['PageHistoryLineEnding'][] = 'FlaggedRevsUIHooks::addToHistLine';
 421+$wgHooks['LocalFile::getHistory'][] = 'FlaggedRevsUIHooks::addToFileHistQuery';
 422+$wgHooks['ImagePageFileHistoryLine'][] = 'FlaggedRevsUIHooks::addToFileHistLine';
422423 # Mark items in RC
423 -$wgHooks['SpecialRecentChangesQuery'][] = 'FlaggedRevsHooks::addToRCQuery';
424 -$wgHooks['SpecialWatchlistQuery'][] = 'FlaggedRevsHooks::addToWatchlistQuery';
425 -$wgHooks['ChangesListInsertArticleLink'][] = 'FlaggedRevsHooks::addToChangeListLine';
 424+$wgHooks['SpecialRecentChangesQuery'][] = 'FlaggedRevsUIHooks::addToRCQuery';
 425+$wgHooks['SpecialWatchlistQuery'][] = 'FlaggedRevsUIHooks::addToWatchlistQuery';
 426+$wgHooks['ChangesListInsertArticleLink'][] = 'FlaggedRevsUIHooks::addToChangeListLine';
426427 # Page review on edit
427 -$wgHooks['ArticleUpdateBeforeRedirect'][] = 'FlaggedRevsHooks::injectPostEditURLParams';
 428+$wgHooks['ArticleUpdateBeforeRedirect'][] = 'FlaggedRevsUIHooks::injectPostEditURLParams';
428429 # Diff-to-stable
429 -$wgHooks['DiffViewHeader'][] = 'FlaggedRevsHooks::onDiffViewHeader';
 430+$wgHooks['DiffViewHeader'][] = 'FlaggedRevsUIHooks::onDiffViewHeader';
430431 # Add diff=review url param alias
431 -$wgHooks['NewDifferenceEngine'][] = 'FlaggedRevsHooks::checkDiffUrl';
 432+$wgHooks['NewDifferenceEngine'][] = 'FlaggedRevsUIHooks::checkDiffUrl';
432433 # Local user account preference
433 -$wgHooks['GetPreferences'][] = 'FlaggedRevsHooks::onGetPreferences';
 434+$wgHooks['GetPreferences'][] = 'FlaggedRevsUIHooks::onGetPreferences';
434435 # Show unreviewed pages links
435 -$wgHooks['CategoryPageView'][] = 'FlaggedRevsHooks::onCategoryPageView';
 436+$wgHooks['CategoryPageView'][] = 'FlaggedRevsUIHooks::onCategoryPageView';
436437 # Review/stability log links
437 -$wgHooks['LogLine'][] = 'FlaggedRevsHooks::logLineLinks';
 438+$wgHooks['LogLine'][] = 'FlaggedRevsUIHooks::logLineLinks';
438439
439440 # Add review notice, backlog notices and CSS/JS and set robots
440 -$wgHooks['BeforePageDisplay'][] = 'FlaggedRevsHooks::onBeforePageDisplay';
 441+$wgHooks['BeforePageDisplay'][] = 'FlaggedRevsUIHooks::onBeforePageDisplay';
441442 # Add global JS vars
442 -$wgHooks['MakeGlobalVariablesScript'][] = 'FlaggedRevsHooks::injectGlobalJSVars';
 443+$wgHooks['MakeGlobalVariablesScript'][] = 'FlaggedRevsUIHooks::injectGlobalJSVars';
443444
444445 # Add flagging data to ApiQueryRevisions
445446 $wgHooks['APIGetAllowedParams'][] = 'FlaggedRevsApiHooks::addApiRevisionParams';
@@ -489,10 +490,10 @@
490491 $wgHooks['GetAutoPromoteGroups'][] = 'FlaggedRevsHooks::checkAutoPromote';
491492
492493 # Check if a page is currently being reviewed
493 -$wgHooks['MediaWikiPerformAction'][] = 'FlaggedRevsHooks::onMediaWikiPerformAction';
 494+$wgHooks['MediaWikiPerformAction'][] = 'FlaggedRevsUIHooks::onMediaWikiPerformAction';
494495
495496 # Actually register special pages
496 -$wgHooks['SpecialPage_initList'][] = 'FlaggedRevsHooks::defineSpecialPages';
 497+$wgHooks['SpecialPage_initList'][] = 'FlaggedRevsUIHooks::defineSpecialPages';
497498
498499 # Stable dump hook
499500 $wgHooks['WikiExporter::dumpStableQuery'][] = 'FlaggedRevsHooks::stableDumpQuery';
@@ -506,7 +507,7 @@
507508 $wgHooks['LoadExtensionSchemaUpdates'][] = 'FlaggedRevsUpdaterHooks::addSchemaUpdates';
508509
509510 # Performance Don't show content on diff
510 -$wgHooks['ArticleContentOnDiff'][] = 'FlaggedRevsHooks::onArticleContentOnDiff';
 511+$wgHooks['ArticleContentOnDiff'][] = 'FlaggedRevsUIHooks::onArticleContentOnDiff';
511512
512513 # ########
513514
@@ -514,15 +515,15 @@
515516 global $wgHooks;
516517 # Mark items in user contribs
517518 if ( !FlaggedRevs::useOnlyIfProtected() ) {
518 - $wgHooks['ContribsPager::getQueryInfo'][] = 'FlaggedRevsHooks::addToContribsQuery';
519 - $wgHooks['ContributionsLineEnding'][] = 'FlaggedRevsHooks::addToContribsLine';
 519+ $wgHooks['ContribsPager::getQueryInfo'][] = 'FlaggedRevsUIHooks::addToContribsQuery';
 520+ $wgHooks['ContributionsLineEnding'][] = 'FlaggedRevsUIHooks::addToContribsLine';
520521 }
521522 if ( FlaggedRevs::useProtectionLevels() ) {
522523 # Add protection form field
523 - $wgHooks['ProtectionForm::buildForm'][] = 'FlaggedRevsHooks::onProtectionForm';
524 - $wgHooks['ProtectionForm::showLogExtract'][] = 'FlaggedRevsHooks::insertStabilityLog';
 524+ $wgHooks['ProtectionForm::buildForm'][] = 'FlaggedRevsUIHooks::onProtectionForm';
 525+ $wgHooks['ProtectionForm::showLogExtract'][] = 'FlaggedRevsUIHooks::insertStabilityLog';
525526 # Save stability settings
526 - $wgHooks['ProtectionForm::save'][] = 'FlaggedRevsHooks::onProtectionSave';
 527+ $wgHooks['ProtectionForm::save'][] = 'FlaggedRevsUIHooks::onProtectionSave';
527528 # Parser stuff
528529 $wgHooks['ParserFirstCallInit'][] = 'FlaggedRevsHooks::onParserFirstCallInit';
529530 $wgHooks['LanguageGetMagic'][] = 'FlaggedRevsHooks::onLanguageGetMagic';
Index: trunk/extensions/FlaggedRevs/FlaggedRevs.hooks.php
@@ -3,148 +3,7 @@
44 * Class containing hooked functions for a FlaggedRevs environment
55 */
66 class FlaggedRevsHooks {
7 - /*
8 - * Register FlaggedRevs special pages as needed.
9 - * Also sets $wgSpecialPages just to be consistent.
10 - */
11 - public static function defineSpecialPages( array &$list ) {
12 - global $wgSpecialPages, $wgUseTagFilter;
13 - // Show special pages only if FlaggedRevs is enabled on some namespaces
14 - if ( !FlaggedRevs::getReviewNamespaces() ) {
15 - return true;
16 - }
17 - $list['RevisionReview'] = $wgSpecialPages['RevisionReview'] = 'RevisionReview';
18 - $list['ReviewedVersions'] = $wgSpecialPages['ReviewedVersions'] = 'ReviewedVersions';
19 - $list['PendingChanges'] = $wgSpecialPages['PendingChanges'] = 'PendingChanges';
20 - // Show tag filtered pending edit page if there are tags
21 - if ( $wgUseTagFilter && ChangeTags::listDefinedTags() ) {
22 - $list['ProblemChanges'] = $wgSpecialPages['ProblemChanges'] = 'ProblemChanges';
23 - }
24 - if ( !FlaggedRevs::useOnlyIfProtected() ) {
25 - $list['ReviewedPages'] = $wgSpecialPages['ReviewedPages'] = 'ReviewedPages';
26 - $list['UnreviewedPages'] = $wgSpecialPages['UnreviewedPages'] = 'UnreviewedPages';
27 - }
28 - $list['QualityOversight'] = $wgSpecialPages['QualityOversight'] = 'QualityOversight';
29 - $list['ValidationStatistics'] = $wgSpecialPages['ValidationStatistics'] = 'ValidationStatistics';
30 - // Protect levels define allowed stability settings
31 - if ( FlaggedRevs::useProtectionLevels() ) {
32 - $list['StablePages'] = $wgSpecialPages['StablePages'] = 'StablePages';
33 - } else {
34 - $list['ConfiguredPages'] = $wgSpecialPages['ConfiguredPages'] = 'ConfiguredPages';
35 - $list['Stabilization'] = $wgSpecialPages['Stabilization'] = 'Stabilization';
36 - }
37 - return true;
38 - }
39 -
407 /**
41 - * Add FlaggedRevs css/js.
42 - */
43 - protected static function injectStyleAndJS() {
44 - global $wgOut, $wgUser;
45 - static $loadedModules = false;
46 - if ( $loadedModules ) {
47 - return true; // don't double-load
48 - }
49 - $loadedModules = true;
50 - $fa = FlaggedPageView::globalArticleInstance();
51 - # Try to only add to relevant pages
52 - if ( !$fa || !$fa->isReviewable() ) {
53 - return true;
54 - }
55 - # Add main CSS & JS files
56 - $wgOut->addModuleStyles( 'ext.flaggedRevs.basic' );
57 - $wgOut->addModules( 'ext.flaggedRevs.advanced' );
58 - # Add review form JS for reviewers
59 - if ( $wgUser->isAllowed( 'review' ) ) {
60 - $wgOut->addModules( 'ext.flaggedRevs.review' );
61 - }
62 - return true;
63 - }
64 -
65 - public static function injectGlobalJSVars( array &$globalVars ) {
66 - # Get the review tags on this wiki
67 - $rTags = FlaggedRevs::getJSTagParams();
68 - $globalVars['wgFlaggedRevsParams'] = $rTags;
69 - # Get page-specific meta-data
70 - $fa = FlaggedPageView::globalArticleInstance();
71 - # Try to only add to relevant pages
72 - if ( $fa && $fa->isReviewable() ) {
73 - $frev = $fa->getStableRev();
74 - $stableId = $frev ? $frev->getRevId() : 0;
75 - } else {
76 - $stableId = null;
77 - }
78 - $globalVars['wgStableRevisionId'] = $stableId;
79 - $revisionContents = (object) array(
80 - 'error' => wfMsgHtml( 'revcontents-error' ),
81 - 'waiting' => wfMsgHtml( 'revcontents-waiting' )
82 - );
83 - $globalVars['wgRevContents'] = $revisionContents;
84 - return true;
85 - }
86 -
87 - /**
88 - * Add FlaggedRevs css for relevant special pages.
89 - * @param OutputPage $out
90 - */
91 - protected static function injectStyleForSpecial( &$out ) {
92 - $title = $out->getTitle();
93 - if ( $title->getNamespace() !== NS_SPECIAL ) {
94 - return true;
95 - }
96 - $spPages = array( 'UnreviewedPages', 'PendingChanges', 'ProblemChanges',
97 - 'Watchlist', 'Recentchanges', 'Contributions', 'Recentchangeslinked' );
98 - foreach ( $spPages as $key ) {
99 - if ( $title->isSpecial( $key ) ) {
100 - $out->addModuleStyles( 'ext.flaggedRevs.basic' ); // CSS only
101 - break;
102 - }
103 - }
104 - return true;
105 - }
106 -
107 - /*
108 - * Add tag notice, CSS/JS, and set robots policy
109 - */
110 - public static function onBeforePageDisplay( &$out, &$skin ) {
111 - if ( $out->isArticleRelated() ) {
112 - $view = FlaggedPageView::singleton();
113 - $view->displayTag(); // show notice bar/icon in subtitle
114 - $view->setRobotPolicy(); // set indexing policy
115 - self::injectStyleAndJS(); // full CSS/JS
116 - } else {
117 - self::maybeAddBacklogNotice( $out ); // RC/Watchlist notice
118 - self::injectStyleForSpecial( $out ); // try special page CSS
119 - }
120 - return true;
121 - }
122 -
123 - // Note: $user may be stubbed
124 - public static function onMediaWikiPerformAction(
125 - $output, $article, Title $title, $user, $request
126 - ) {
127 - $fa = FlaggedPage::getTitleInstance( $title );
128 - self::maybeMarkUnderReview( $fa, $request );
129 - return true;
130 - }
131 -
132 - // Mark when an unreviewed page is being reviewed
133 - protected static function maybeMarkUnderReview( FlaggedPage $fa, WebRequest $request ) {
134 - global $wgUser;
135 - if ( !$request->getInt( 'reviewing' ) && !$request->getInt( 'rcid' ) ) {
136 - return true; // not implied by URL
137 - }
138 - # Set a key to note when someone is reviewing this.
139 - # NOTE: diff-to-stable views already handled elsewhere.
140 - if ( $fa->isReviewable() && !$fa->getStable() // not reviewed yet
141 - && $fa->getTitle()->userCan( 'review' ) )
142 - {
143 - FRUserActivity::setUserReviewingPage( $wgUser, $fa->getID() );
144 - }
145 - return true;
146 - }
147 -
148 - /**
1498 * Update flaggedrevs table on revision restore
1509 */
15110 public static function onRevisionRestore( $title, Revision $revision, $oldPageID ) {
@@ -1133,526 +992,6 @@
1134993 return true;
1135994 }
1136995
1137 - /** Add user preferences */
1138 - public static function onGetPreferences( $user, array &$preferences ) {
1139 - // Box or bar UI
1140 - $preferences['flaggedrevssimpleui'] =
1141 - array(
1142 - 'type' => 'radio',
1143 - 'section' => 'flaggedrevs/flaggedrevs-ui',
1144 - 'label-message' => 'flaggedrevs-pref-UI',
1145 - 'options' => array(
1146 - wfMsg( 'flaggedrevs-pref-UI-0' ) => 0,
1147 - wfMsg( 'flaggedrevs-pref-UI-1' ) => 1,
1148 - ),
1149 - );
1150 - // Default versions...
1151 - $preferences['flaggedrevsstable'] =
1152 - array(
1153 - 'type' => 'toggle',
1154 - 'section' => 'flaggedrevs/flaggedrevs-ui',
1155 - 'label-message' => 'flaggedrevs-prefs-stable',
1156 - );
1157 - // Review-related rights...
1158 - if ( $user->isAllowed( 'review' ) ) {
1159 - // Watching reviewed pages
1160 - $preferences['flaggedrevswatch'] =
1161 - array(
1162 - 'type' => 'toggle',
1163 - 'section' => 'watchlist/advancedwatchlist',
1164 - 'label-message' => 'flaggedrevs-prefs-watch',
1165 - );
1166 - // Diff-to-stable on edit
1167 - $preferences['flaggedrevseditdiffs'] =
1168 - array(
1169 - 'type' => 'toggle',
1170 - 'section' => 'editing/advancedediting',
1171 - 'label-message' => 'flaggedrevs-prefs-editdiffs',
1172 - );
1173 - // Diff-to-stable on draft view
1174 - $preferences['flaggedrevsviewdiffs'] =
1175 - array(
1176 - 'type' => 'toggle',
1177 - 'section' => 'flaggedrevs/flaggedrevs-ui',
1178 - 'label-message' => 'flaggedrevs-prefs-viewdiffs',
1179 - );
1180 - }
1181 - return true;
1182 - }
1183 -
1184 - public static function logLineLinks(
1185 - $type, $action, $title, $params, &$comment, &$rv, $ts
1186 - ) {
1187 - if ( !$title ) {
1188 - return true; // sanity check
1189 - }
1190 - // Stability log
1191 - if ( $type == 'stable' && FlaggedRevsLog::isStabilityAction( $action ) ) {
1192 - $rv .= FlaggedRevsLogView::stabilityLogLinks( $title, $ts, $params );
1193 - // Review log
1194 - } elseif ( $type == 'review' && FlaggedRevsLog::isReviewAction( $action ) ) {
1195 - $rv .= FlaggedRevsLogView::reviewLogLinks( $action, $title, $params );
1196 - }
1197 - return true;
1198 - }
1199 -
1200 - public static function onImagePageFindFile( $imagePage, &$normalFile, &$displayFile ) {
1201 - $view = FlaggedPageView::singleton();
1202 - $view->imagePageFindFile( $normalFile, $displayFile );
1203 - return true;
1204 - }
1205 -
1206 - // MonoBook et al: $contentActions is all the tabs
1207 - // Vector et al: $contentActions is all the action tabs...unused
1208 - public static function onSkinTemplateTabs( Skin $skin, array &$contentActions ) {
1209 - if ( $skin instanceof SkinVector ) {
1210 - // *sigh*...skip, dealt with in setNavigation()
1211 - return true;
1212 - }
1213 - // Note: $wgArticle sometimes not set here
1214 - if ( FlaggedPageView::globalArticleInstance() != null ) {
1215 - $view = FlaggedPageView::singleton();
1216 - $view->setActionTabs( $skin, $contentActions );
1217 - $view->setViewTabs( $skin, $contentActions, 'flat' );
1218 - }
1219 - return true;
1220 - }
1221 -
1222 - // Vector et al: $links is all the tabs (2 levels)
1223 - public static function onSkinTemplateNavigation( Skin $skin, array &$links ) {
1224 - // Note: $wgArticle sometimes not set here
1225 - if ( FlaggedPageView::globalArticleInstance() != null ) {
1226 - $view = FlaggedPageView::singleton();
1227 - $view->setActionTabs( $skin, $links['actions'] );
1228 - $view->setViewTabs( $skin, $links['views'], 'nav' );
1229 - }
1230 - return true;
1231 - }
1232 -
1233 - public static function onArticleViewHeader( &$article, &$outputDone, &$useParserCache ) {
1234 - $view = FlaggedPageView::singleton();
1235 - $view->addStableLink( $outputDone, $useParserCache );
1236 - $view->setPageContent( $outputDone, $useParserCache );
1237 - return true;
1238 - }
1239 -
1240 - public static function overrideRedirect(
1241 - Title $title, WebRequest $request, &$ignoreRedirect, &$target, Article &$article
1242 - ) {
1243 - global $wgMemc, $wgParserCacheExpireTime;
1244 - $fa = FlaggedPage::getTitleInstance( $title ); // on $wgTitle
1245 - if ( !$fa->isReviewable() ) {
1246 - return true; // nothing to do
1247 - }
1248 - # Viewing an old reviewed version...
1249 - if ( $request->getVal( 'stableid' ) ) {
1250 - $ignoreRedirect = true; // don't redirect (same as ?oldid=x)
1251 - return true;
1252 - }
1253 - $srev = $fa->getStableRev();
1254 - $view = FlaggedPageView::singleton();
1255 - # Check if we are viewing an unsynced stable version...
1256 - if ( $srev && $view->showingStable() && $srev->getRevId() != $article->getLatest() ) {
1257 - # Check the stable redirect properties from the cache...
1258 - $key = wfMemcKey( 'flaggedrevs', 'overrideRedirect', $article->getId() );
1259 - $tuple = FlaggedRevs::getMemcValue( $wgMemc->get( $key ), $article );
1260 - if ( is_array( $tuple ) ) { // cache hit
1261 - list( $ignoreRedirect, $target ) = $tuple;
1262 - } else { // cache miss; fetch the stable rev text...
1263 - $text = $srev->getRevText();
1264 - $redirect = $fa->getRedirectURL( Title::newFromRedirectRecurse( $text ) );
1265 - if ( $redirect ) {
1266 - $target = $redirect; // use stable redirect
1267 - } else {
1268 - $ignoreRedirect = true; // make MW skip redirection
1269 - }
1270 - $data = FlaggedRevs::makeMemcObj( array( $ignoreRedirect, $target ) );
1271 - $wgMemc->set( $key, $data, $wgParserCacheExpireTime ); // cache results
1272 - }
1273 - $clearEnvironment = (bool)$target;
1274 - # Check if the we are viewing a draft or synced stable version...
1275 - } else {
1276 - # In both cases, we can just let MW use followRedirect()
1277 - # on the draft as normal, avoiding any page text hits.
1278 - $clearEnvironment = $article->isRedirect();
1279 - }
1280 - # Environment (e.g. $wgTitle) will change in MediaWiki::initializeArticle
1281 - if ( $clearEnvironment ) $view->clear();
1282 - return true;
1283 - }
1284 -
1285 - public static function addToEditView( &$editPage ) {
1286 - $view = FlaggedPageView::singleton();
1287 - $view->addToEditView( $editPage );
1288 - return true;
1289 - }
1290 -
1291 - public static function onBeforeEditButtons( &$editPage, &$buttons ) {
1292 - $view = FlaggedPageView::singleton();
1293 - $view->changeSaveButton( $editPage, $buttons );
1294 - return true;
1295 - }
1296 -
1297 - public static function onNoSuchSection( &$editPage, &$s ) {
1298 - $view = FlaggedPageView::singleton();
1299 - $view->addToNoSuchSection( $editPage, $s );
1300 - return true;
1301 - }
1302 -
1303 - public static function addToHistView( &$article ) {
1304 - $view = FlaggedPageView::singleton();
1305 - $view->addToHistView();
1306 - return true;
1307 - }
1308 -
1309 - public static function onCategoryPageView( &$category ) {
1310 - $view = FlaggedPageView::singleton();
1311 - $view->addToCategoryView();
1312 - return true;
1313 - }
1314 -
1315 - public static function onSkinAfterContent( &$data ) {
1316 - global $wgOut;
1317 - if ( $wgOut->isArticleRelated()
1318 - && FlaggedPageView::globalArticleInstance() != null )
1319 - {
1320 - $view = FlaggedPageView::singleton();
1321 - $view->addReviewNotes( $data );
1322 - $view->addReviewForm( $data );
1323 - $view->addVisibilityLink( $data );
1324 - }
1325 - return true;
1326 - }
1327 -
1328 - public static function addToHistQuery( HistoryPager $pager, array &$queryInfo ) {
1329 - $flaggedArticle = FlaggedPage::getArticleInstance( $pager->getArticle() );
1330 - # Non-content pages cannot be validated. Stable version must exist.
1331 - if ( $flaggedArticle->isReviewable() && $flaggedArticle->getStableRev() ) {
1332 - # Highlight flaggedrevs
1333 - $queryInfo['tables'][] = 'flaggedrevs';
1334 - $queryInfo['fields'][] = 'fr_quality';
1335 - $queryInfo['fields'][] = 'fr_user';
1336 - $queryInfo['fields'][] = 'fr_flags';
1337 - $queryInfo['join_conds']['flaggedrevs'] = array( 'LEFT JOIN',
1338 - "fr_page_id = rev_page AND fr_rev_id = rev_id" );
1339 - # Find reviewer name. Sanity check that no extensions added a `user` query.
1340 - if ( !in_array( 'user', $queryInfo['tables'] ) ) {
1341 - $queryInfo['tables'][] = 'user';
1342 - $queryInfo['fields'][] = 'user_name AS reviewer';
1343 - $queryInfo['join_conds']['user'] = array( 'LEFT JOIN', "user_id = fr_user" );
1344 - }
1345 - }
1346 - return true;
1347 - }
1348 -
1349 - public static function addToFileHistQuery(
1350 - File $file, array &$tables, array &$fields, &$conds, array &$opts, array &$join_conds
1351 - ) {
1352 - if ( !$file->isLocal() ) {
1353 - return true; // local files only
1354 - }
1355 - $flaggedArticle = FlaggedPage::getTitleInstance( $file->getTitle() );
1356 - # Non-content pages cannot be validated. Stable version must exist.
1357 - if ( $flaggedArticle->isReviewable() && $flaggedArticle->getStableRev() ) {
1358 - $tables[] = 'flaggedrevs';
1359 - $fields[] = 'MAX(fr_quality) AS fr_quality';
1360 - # Avoid duplicate rows due to multiple revs with the same sha-1 key
1361 -
1362 - # This is a stupid hack to get all the field names in our GROUP BY
1363 - # clause. Postgres yells at you for not including all of the selected
1364 - # columns, so grab the full list, unset the two we actually want to
1365 - # order by, then append the rest of them to our two. It would be
1366 - # REALLY nice if we handled this automagically in makeSelectOptions()
1367 - # or something *sigh*
1368 - $groupBy = OldLocalFile::selectFields();
1369 - unset( $groupBy[ array_search( 'oi_name', $groupBy ) ] );
1370 - unset( $groupBy[ array_search( 'oi_timestamp', $groupBy ) ] );
1371 - $opts['GROUP BY'] = 'oi_name,oi_timestamp,' . implode( ',', $groupBy );
1372 -
1373 - $join_conds['flaggedrevs'] = array( 'LEFT JOIN',
1374 - 'oi_sha1 = fr_img_sha1 AND oi_timestamp = fr_img_timestamp' );
1375 - }
1376 - return true;
1377 - }
1378 -
1379 - public static function addToContribsQuery( $pager, array &$queryInfo ) {
1380 - # Highlight flaggedrevs
1381 - $queryInfo['tables'][] = 'flaggedrevs';
1382 - $queryInfo['fields'][] = 'fr_quality';
1383 - $queryInfo['join_conds']['flaggedrevs'] = array( 'LEFT JOIN',
1384 - "fr_page_id = rev_page AND fr_rev_id = rev_id" );
1385 - # Highlight unchecked content
1386 - $queryInfo['tables'][] = 'flaggedpages';
1387 - $queryInfo['fields'][] = 'fp_stable';
1388 - $queryInfo['fields'][] = 'fp_pending_since';
1389 - $queryInfo['join_conds']['flaggedpages'] = array( 'LEFT JOIN', "fp_page_id = rev_page" );
1390 - return true;
1391 - }
1392 -
1393 - public static function addToRCQuery(
1394 - &$conds, array &$tables, array &$join_conds, $opts, &$query_opts, &$select
1395 - ) {
1396 - $tables[] = 'flaggedpages';
1397 - $join_conds['flaggedpages'] = array( 'LEFT JOIN', 'fp_page_id = rc_cur_id' );
1398 - if ( is_array( $select ) ) { // RCL
1399 - $select[] = 'fp_stable';
1400 - $select[] = 'fp_pending_since';
1401 - }
1402 - return true;
1403 - }
1404 -
1405 - public static function addToWatchlistQuery(
1406 - &$conds, array &$tables, array &$join_conds, array &$fields
1407 - ) {
1408 - global $wgUser;
1409 - if ( $wgUser->isAllowed( 'review' ) ) {
1410 - $fields[] = 'fp_stable';
1411 - $fields[] = 'fp_pending_since';
1412 - $tables[] = 'flaggedpages';
1413 - $join_conds['flaggedpages'] = array( 'LEFT JOIN', 'fp_page_id = rc_cur_id' );
1414 - }
1415 - return true;
1416 - }
1417 -
1418 - public static function addToHistLine( HistoryPager $history, $row, &$s, &$liClasses ) {
1419 - $fa = FlaggedPage::getArticleInstance( $history->getArticle() );
1420 - if ( !$fa->isReviewable() ) {
1421 - return true; // nothing to do here
1422 - }
1423 - # Fetch and process cache the stable revision
1424 - if ( !isset( $history->fr_stableRevId ) ) {
1425 - $srev = $fa->getStableRev();
1426 - $history->fr_stableRevId = $srev ? $srev->getRevId() : null;
1427 - $history->fr_stableRevUTS = $srev ? // bug 15515
1428 - wfTimestamp( TS_UNIX, $srev->getRevTimestamp() ) : null;
1429 - $history->fr_pendingRevs = false;
1430 - }
1431 - if ( !$history->fr_stableRevId ) {
1432 - return true; // nothing to do here
1433 - }
1434 - $title = $history->getArticle()->getTitle();
1435 - $revId = (int)$row->rev_id;
1436 - // Pending revision: highlight and add diff link
1437 - $link = $class = '';
1438 - if ( wfTimestamp( TS_UNIX, $row->rev_timestamp ) > $history->fr_stableRevUTS ) {
1439 - $class = 'flaggedrevs-pending';
1440 - $link = wfMsgExt( 'revreview-hist-pending-difflink', 'parseinline',
1441 - $title->getPrefixedText(), $history->fr_stableRevId, $revId );
1442 - $link = '<span class="plainlinks">' . $link . '</span>';
1443 - $history->fr_pendingRevs = true; // pending rev shown above stable
1444 - // Reviewed revision: highlight and add link
1445 - } elseif ( isset( $row->fr_quality ) ) {
1446 - if ( !( $row->rev_deleted & Revision::DELETED_TEXT ) ) {
1447 - # Add link to stable version of *this* rev, if any
1448 - list( $link, $class ) = self::markHistoryRow( $title, $row );
1449 - # Space out and demark the stable revision
1450 - if ( $revId == $history->fr_stableRevId && $history->fr_pendingRevs ) {
1451 - $liClasses[] = 'fr-hist-stable-margin';
1452 - }
1453 - }
1454 - }
1455 - # Style the row as needed
1456 - if ( $class ) $s = "<span class='$class'>$s</span>";
1457 - # Add stable old version link
1458 - if ( $link ) $s .= " <small>$link</small>";
1459 - return true;
1460 - }
1461 -
1462 - /**
1463 - * Make stable version link and return the css
1464 - * @param Title $title
1465 - * @param Row $row, from history page
1466 - * @return array (string,string)
1467 - */
1468 - protected static function markHistoryRow( Title $title, $row ) {
1469 - if ( !isset( $row->fr_quality ) ) {
1470 - return array( "", "" ); // not reviewed
1471 - }
1472 - $liCss = FlaggedRevsXML::getQualityColor( $row->fr_quality );
1473 - $flags = explode( ',', $row->fr_flags );
1474 - if ( in_array( 'auto', $flags ) ) {
1475 - $msg = ( $row->fr_quality >= 1 )
1476 - ? 'revreview-hist-quality-auto'
1477 - : 'revreview-hist-basic-auto';
1478 - $css = ( $row->fr_quality >= 1 )
1479 - ? 'fr-hist-quality-auto'
1480 - : 'fr-hist-basic-auto';
1481 - } else {
1482 - $msg = ( $row->fr_quality >= 1 )
1483 - ? 'revreview-hist-quality-user'
1484 - : 'revreview-hist-basic-user';
1485 - $css = ( $row->fr_quality >= 1 )
1486 - ? 'fr-hist-quality-user'
1487 - : 'fr-hist-basic-user';
1488 - }
1489 - $name = isset( $row->reviewer ) ?
1490 - $row->reviewer : User::whoIs( $row->fr_user );
1491 - $link = wfMsgExt( $msg, 'parseinline', $title->getPrefixedDBkey(), $row->rev_id, $name );
1492 - $link = "<span class='$css plainlinks'>[$link]</span>";
1493 - return array( $link, $liCss );
1494 - }
1495 -
1496 - public static function addToFileHistLine( $hist, File $file, &$s, &$rowClass ) {
1497 - if ( !$file->isVisible() ) {
1498 - return true; // Don't bother showing notice for deleted revs
1499 - }
1500 - # Quality level for old versions selected all at once.
1501 - # Commons queries cannot be done all at once...
1502 - if ( !$file->isOld() || !$file->isLocal() ) {
1503 - $dbr = wfGetDB( DB_SLAVE );
1504 - $quality = $dbr->selectField( 'flaggedrevs', 'fr_quality',
1505 - array( 'fr_img_sha1' => $file->getSha1(),
1506 - 'fr_img_timestamp' => $dbr->timestamp( $file->getTimestamp() ) ),
1507 - __METHOD__
1508 - );
1509 - } else {
1510 - $quality = is_null( $file->quality ) ? false : $file->quality;
1511 - }
1512 - # If reviewed, class the line
1513 - if ( $quality !== false ) {
1514 - $rowClass = FlaggedRevsXML::getQualityColor( $quality );
1515 - }
1516 - return true;
1517 - }
1518 -
1519 - public static function addToContribsLine( $contribs, &$ret, $row ) {
1520 - $namespaces = FlaggedRevs::getReviewNamespaces();
1521 - if ( !in_array( $row->page_namespace, $namespaces ) ) {
1522 - // do nothing
1523 - } elseif ( isset( $row->fr_quality ) ) {
1524 - $ret = '<span class="' . FlaggedRevsXML::getQualityColor( $row->fr_quality ) .
1525 - '">' . $ret . '</span>';
1526 - } elseif ( isset( $row->fp_pending_since )
1527 - && $row->rev_timestamp >= $row->fp_pending_since ) // bug 15515
1528 - {
1529 - $ret = '<span class="flaggedrevs-pending">' . $ret . '</span>';
1530 - } elseif ( !isset( $row->fp_stable ) ) {
1531 - $ret = '<span class="flaggedrevs-unreviewed">' . $ret . '</span>';
1532 - }
1533 - return true;
1534 - }
1535 -
1536 - public static function addToChangeListLine( &$list, &$articlelink, &$s, RecentChange &$rc ) {
1537 - global $wgUser;
1538 - $title = $rc->getTitle(); // convenience
1539 - if ( !FlaggedRevs::inReviewNamespace( $title )
1540 - || empty( $rc->mAttribs['rc_this_oldid'] ) // rev, not log
1541 - || !array_key_exists( 'fp_stable', $rc->mAttribs ) )
1542 - {
1543 - return true; // confirm that page is in reviewable namespace
1544 - }
1545 - $rlink = '';
1546 - // page is not reviewed
1547 - if ( $rc->mAttribs['fp_stable'] == null ) {
1548 - // Is this a config were pages start off reviewable?
1549 - // Hide notice from non-reviewers due to vandalism concerns (bug 24002).
1550 - if ( !FlaggedRevs::useOnlyIfProtected() && $wgUser->isAllowed( 'review' ) ) {
1551 - $rlink = wfMsgHtml( 'revreview-unreviewedpage' );
1552 - $css = 'flaggedrevs-unreviewed';
1553 - }
1554 - // page is reviewed and has pending edits (use timestamps; bug 15515)
1555 - } elseif ( isset( $rc->mAttribs['fp_pending_since'] ) &&
1556 - $rc->mAttribs['rc_timestamp'] >= $rc->mAttribs['fp_pending_since'] )
1557 - {
1558 - $rlink = $list->skin->link(
1559 - $title,
1560 - wfMsgHtml( 'revreview-reviewlink' ),
1561 - array( 'title' => wfMsg( 'revreview-reviewlink-title' ) ),
1562 - array( 'oldid' => $rc->mAttribs['fp_stable'], 'diff' => 'cur' )
1563 - );
1564 - $css = 'flaggedrevs-pending';
1565 - }
1566 - if ( $rlink != '' ) {
1567 - $articlelink .= " <span class=\"mw-fr-reviewlink $css\">[$rlink]</span>";
1568 - }
1569 - return true;
1570 - }
1571 -
1572 - public static function injectPostEditURLParams( $article, &$sectionAnchor, &$extraQuery ) {
1573 - // Note: $wgArticle sometimes not set here
1574 - if ( FlaggedPageView::globalArticleInstance() != null ) {
1575 - $view = FlaggedPageView::singleton();
1576 - $view->injectPostEditURLParams( $sectionAnchor, $extraQuery );
1577 - }
1578 - return true;
1579 - }
1580 -
1581 - // diff=review param (bug 16923)
1582 - public static function checkDiffUrl( $titleObj, &$mOldid, &$mNewid, $old, $new ) {
1583 - if ( $new === 'review' && isset( $titleObj ) ) {
1584 - $frev = FlaggedRevision::newFromStable( $titleObj );
1585 - if ( $frev ) {
1586 - $mOldid = $frev->getRevId(); // stable
1587 - $mNewid = 0; // cur
1588 - }
1589 - }
1590 - return true;
1591 - }
1592 -
1593 - public static function onDiffViewHeader( $diff, $oldRev, $newRev ) {
1594 - self::injectStyleAndJS();
1595 - $view = FlaggedPageView::singleton();
1596 - $view->setViewFlags( $diff, $oldRev, $newRev );
1597 - $view->addToDiffView( $diff, $oldRev, $newRev );
1598 - return true;
1599 - }
1600 -
1601 - /*
1602 - * If an article is reviewable, get custom article contents from the FlaggedPageView
1603 - */
1604 - public static function onArticleContentOnDiff( $diffEngine, $out ) {
1605 - $fa = FlaggedPage::getTitleInstance( $out->getTitle() );
1606 - if ( !$fa->isReviewable() ) {
1607 - return true; // nothing to do
1608 - }
1609 - $view = FlaggedPageView::singleton();
1610 - $view->addCustomContentHtml( $out, $diffEngine->getNewid() );
1611 - return false;
1612 - }
1613 -
1614 - public static function addRevisionIDField( $editPage, $out ) {
1615 - $view = FlaggedPageView::singleton();
1616 - $view->addRevisionIDField( $editPage, $out );
1617 - return true;
1618 - }
1619 -
1620 - public static function addReviewCheck( $editPage, &$checkboxes, &$tabindex ) {
1621 - $view = FlaggedPageView::singleton();
1622 - $view->addReviewCheck( $editPage, $checkboxes, $tabindex );
1623 - return true;
1624 - }
1625 -
1626 - protected static function maybeAddBacklogNotice( OutputPage &$out ) {
1627 - global $wgUser;
1628 - if ( !$wgUser->isAllowed( 'review' ) ) {
1629 - return true; // not relevant to user
1630 - }
1631 - $namespaces = FlaggedRevs::getReviewNamespaces();
1632 - $watchlist = SpecialPage::getTitleFor( 'Watchlist' );
1633 - # Add notice to watchlist about pending changes...
1634 - if ( $out->getTitle()->equals( $watchlist ) && $namespaces ) {
1635 - $dbr = wfGetDB( DB_SLAVE, 'watchlist' ); // consistency with watchlist
1636 - $watchedOutdated = (bool)$dbr->selectField(
1637 - array( 'watchlist', 'page', 'flaggedpages' ),
1638 - '1', // existence
1639 - array( 'wl_user' => $wgUser->getId(), // this user
1640 - 'wl_namespace' => $namespaces, // reviewable
1641 - 'wl_namespace = page_namespace',
1642 - 'wl_title = page_title',
1643 - 'fp_page_id = page_id',
1644 - 'fp_pending_since IS NOT NULL', // edits pending
1645 - ), __METHOD__
1646 - );
1647 - # Give a notice if pages on the users's wachlist have pending edits
1648 - if ( $watchedOutdated ) {
1649 - $css = 'plainlinks fr-watchlist-pending-notice';
1650 - $out->prependHTML( "<div id='mw-fr-watchlist-pending-notice' class='$css'>" .
1651 - wfMsgExt( 'flaggedrevs-watched-pending', 'parseinline' ) . "</div>" );
1652 - }
1653 - }
1654 - return true;
1655 - }
1656 -
1657996 public static function stableDumpQuery( array &$tables, array &$opts, array &$join ) {
1658997 $namespaces = FlaggedRevs::getReviewNamespaces();
1659998 if ( $namespaces ) {
@@ -1668,189 +1007,6 @@
16691008 return false; // final
16701009 }
16711010
1672 - // Add selector of review "protection" options
1673 - // Code stolen from Stabilization (which was stolen from ProtectionForm)
1674 - public static function onProtectionForm( Article $article, &$output ) {
1675 - global $wgUser, $wgOut, $wgRequest, $wgLang;
1676 - if ( !$article->exists() ) {
1677 - return true; // nothing to do
1678 - } elseif ( !FlaggedRevs::inReviewNamespace( $article->getTitle() ) ) {
1679 - return true; // not a reviewable page
1680 - }
1681 - $form = new PageStabilityProtectForm( $wgUser );
1682 - $form->setPage( $article->getTitle() );
1683 - # Can the user actually do anything?
1684 - $isAllowed = $form->isAllowed();
1685 - $disabledAttrib = $isAllowed ?
1686 - array() : array( 'disabled' => 'disabled' );
1687 -
1688 - # Get the current config/expiry
1689 - $config = FlaggedPageConfig::getStabilitySettings( $article->getTitle(), FR_MASTER );
1690 - $oldExpirySelect = ( $config['expiry'] == 'infinity' ) ? 'infinite' : 'existing';
1691 -
1692 - # Load requested restriction level, default to current level...
1693 - $restriction = $wgRequest->getVal( 'mwStabilityLevel',
1694 - FlaggedPageConfig::getProtectionLevel( $config ) );
1695 - # Load the requested expiry time (dropdown)
1696 - $expirySelect = $wgRequest->getVal( 'mwStabilizeExpirySelection', $oldExpirySelect );
1697 - # Load the requested expiry time (field)
1698 - $expiryOther = $wgRequest->getVal( 'mwStabilizeExpiryOther', '' );
1699 - if ( $expiryOther != '' ) $expirySelect = 'othertime'; // mutual exclusion
1700 -
1701 - # Add an extra row to the protection fieldset tables.
1702 - # Includes restriction dropdown and expiry dropdown & field.
1703 - $output .= "<tr><td>";
1704 - $output .= Xml::openElement( 'fieldset' );
1705 - $legendMsg = wfMsgExt( 'flaggedrevs-protect-legend', 'parseinline' );
1706 - $output .= "<legend>{$legendMsg}</legend>";
1707 - # Add a "no restrictions" level
1708 - $effectiveLevels = FlaggedRevs::getRestrictionLevels();
1709 - array_unshift( $effectiveLevels, "none" );
1710 - # Show all restriction levels in a <select>...
1711 - $attribs = array(
1712 - 'id' => 'mwStabilityLevel',
1713 - 'name' => 'mwStabilityLevel',
1714 - 'size' => count( $effectiveLevels ),
1715 - ) + $disabledAttrib;
1716 - $output .= Xml::openElement( 'select', $attribs );
1717 - foreach ( $effectiveLevels as $limit ) {
1718 - if ( $limit == 'none' ) {
1719 - $label = wfMsg( 'flaggedrevs-protect-none' );
1720 - } else {
1721 - $label = wfMsg( 'flaggedrevs-protect-' . $limit );
1722 - }
1723 - // Default to the key itself if no UI message
1724 - if ( wfEmptyMsg( 'flaggedrevs-protect-' . $limit, $label ) ) {
1725 - $label = 'flaggedrevs-protect-' . $limit;
1726 - }
1727 - $output .= Xml::option( $label, $limit, $limit == $restriction );
1728 - }
1729 - $output .= Xml::closeElement( 'select' );
1730 -
1731 - # Get expiry dropdown <select>...
1732 - $scExpiryOptions = wfMsgForContent( 'protect-expiry-options' );
1733 - $showProtectOptions = ( $scExpiryOptions !== '-' && $isAllowed );
1734 - # Add the current expiry as an option
1735 - $expiryFormOptions = '';
1736 - if ( $config['expiry'] != 'infinity' ) {
1737 - $timestamp = $wgLang->timeanddate( $config['expiry'] );
1738 - $d = $wgLang->date( $config['expiry'] );
1739 - $t = $wgLang->time( $config['expiry'] );
1740 - $expiryFormOptions .=
1741 - Xml::option(
1742 - wfMsg( 'protect-existing-expiry', $timestamp, $d, $t ),
1743 - 'existing',
1744 - $expirySelect == 'existing'
1745 - ) . "\n";
1746 - }
1747 - $expiryFormOptions .= Xml::option( wfMsg( 'protect-othertime-op' ), 'othertime' ) . "\n";
1748 - # Add custom dropdown levels (from MediaWiki message)
1749 - foreach ( explode( ',', $scExpiryOptions ) as $option ) {
1750 - if ( strpos( $option, ":" ) === false ) {
1751 - $show = $value = $option;
1752 - } else {
1753 - list( $show, $value ) = explode( ":", $option );
1754 - }
1755 - $show = htmlspecialchars( $show );
1756 - $value = htmlspecialchars( $value );
1757 - $expiryFormOptions .= Xml::option( $show, $value, $expirySelect == $value ) . "\n";
1758 - }
1759 - # Actually add expiry dropdown to form
1760 - $output .= "<table>"; // expiry table start
1761 - if ( $showProtectOptions && $isAllowed ) {
1762 - $output .= "
1763 - <tr>
1764 - <td class='mw-label'>" .
1765 - Xml::label( wfMsg( 'stabilization-expiry' ),
1766 - 'mwStabilizeExpirySelection' ) .
1767 - "</td>
1768 - <td class='mw-input'>" .
1769 - Xml::tags( 'select',
1770 - array(
1771 - 'id' => 'mwStabilizeExpirySelection',
1772 - 'name' => 'mwStabilizeExpirySelection',
1773 - 'onchange' => 'onFRChangeExpiryDropdown()',
1774 - ) + $disabledAttrib,
1775 - $expiryFormOptions ) .
1776 - "</td>
1777 - </tr>";
1778 - }
1779 - # Add custom expiry field to form
1780 - $attribs = array( 'id' => 'mwStabilizeExpiryOther',
1781 - 'onkeyup' => 'onFRChangeExpiryField()' ) + $disabledAttrib;
1782 - $output .= "
1783 - <tr>
1784 - <td class='mw-label'>" .
1785 - Xml::label( wfMsg( 'stabilization-othertime' ), 'mwStabilizeExpiryOther' ) .
1786 - '</td>
1787 - <td class="mw-input">' .
1788 - Xml::input( 'mwStabilizeExpiryOther', 50, $expiryOther, $attribs ) .
1789 - '</td>
1790 - </tr>';
1791 - $output .= "</table>"; // expiry table end
1792 - # Close field set and table row
1793 - $output .= Xml::closeElement( 'fieldset' );
1794 - $output .= "</td></tr>";
1795 -
1796 - # Add some javascript for expiry dropdowns
1797 - $wgOut->addScript(
1798 - "<script type=\"text/javascript\">
1799 - function onFRChangeExpiryDropdown() {
1800 - document.getElementById('mwStabilizeExpiryOther').value = '';
1801 - }
1802 - function onFRChangeExpiryField() {
1803 - document.getElementById('mwStabilizeExpirySelection').value = 'othertime';
1804 - }
1805 - </script>"
1806 - );
1807 - return true;
1808 - }
1809 -
1810 - // Add stability log extract to protection form
1811 - public static function insertStabilityLog( Article $article, OutputPage $out ) {
1812 - if ( !$article->exists() ) {
1813 - return true; // nothing to do
1814 - } else if ( !FlaggedRevs::inReviewNamespace( $article->getTitle() ) ) {
1815 - return true; // not a reviewable page
1816 - }
1817 - # Show relevant lines from the stability log:
1818 - $out->addHTML( Xml::element( 'h2', null, LogPage::logName( 'stable' ) ) );
1819 - LogEventsList::showLogExtract( $out, 'stable', $article->getTitle()->getPrefixedText() );
1820 - return true;
1821 - }
1822 -
1823 - // Update stability config from request
1824 - public static function onProtectionSave( Article $article, &$errorMsg ) {
1825 - global $wgUser, $wgRequest;
1826 - if ( !$article->exists() ) {
1827 - return true; // simple custom levels set for action=protect
1828 - } elseif ( !FlaggedRevs::inReviewNamespace( $article->getTitle() ) ) {
1829 - return true; // not a reviewable page
1830 - } elseif ( wfReadOnly() || !$wgUser->isAllowed( 'stablesettings' ) ) {
1831 - return true; // user cannot change anything
1832 - }
1833 - $form = new PageStabilityProtectForm( $wgUser );
1834 - $form->setPage( $article->getTitle() ); // target page
1835 - $permission = $wgRequest->getVal( 'mwStabilityLevel' );
1836 - if ( $permission == "none" ) {
1837 - $permission = ''; // 'none' => ''
1838 - }
1839 - $form->setAutoreview( $permission ); // protection level (autoreview restriction)
1840 - $form->setWatchThis( null ); // protection form already has a watch check
1841 - $form->setReasonExtra( $wgRequest->getText( 'mwProtect-reason' ) ); // manual
1842 - $form->setReasonSelection( $wgRequest->getVal( 'wpProtectReasonSelection' ) ); // dropdown
1843 - $form->setExpiryCustom( $wgRequest->getVal( 'mwStabilizeExpiryOther' ) ); // manual
1844 - $form->setExpirySelection( $wgRequest->getVal( 'mwStabilizeExpirySelection' ) ); // dropdown
1845 - $form->ready(); // params all set
1846 - if ( $wgRequest->wasPosted() && $form->isAllowed() ) {
1847 - $status = $form->submit();
1848 - if ( $status !== true ) {
1849 - $errorMsg = wfMsg( $status ); // some error message
1850 - }
1851 - }
1852 - return true;
1853 - }
1854 -
18551011 public static function getUnitTests( &$files ) {
18561012 $files[] = dirname( __FILE__ ) . '/maintenance/tests/FRInclusionManagerTest.php';
18571013 $files[] = dirname( __FILE__ ) . '/maintenance/tests/FRUserCountersTest.php';
Index: trunk/extensions/FlaggedRevs/presentation/RevisionReviewFormGUI.php
@@ -1,392 +0,0 @@
2 -<?php
3 -/**
4 - * Main review form UI
5 - *
6 - * NOTE: use ONLY for diff-to-stable views and page version views
7 - */
8 -class RevisionReviewFormGUI {
9 - protected $user, $article, $rev;
10 - protected $refRev = null;
11 - protected $topNotice = '';
12 - protected $templateIDs = null, $imageSHA1Keys = null;
13 -
14 - /**
15 - * Generates a brief review form for a page
16 - * @param User $user
17 - * @param FlaggedPage $article
18 - * @param Revision $rev
19 - */
20 - public function __construct( User $user, FlaggedPage $article, Revision $rev ) {
21 - $this->user = $user;
22 - $this->article = $article;
23 - $this->rev = $rev;
24 - }
25 -
26 - /*
27 - * Call this only when the form is shown on a diff:
28 - * (a) Shows the "reject" button
29 - * (b) Default the rating tags to those of $this->rev (if flagged)
30 - * @param Revision $refRev Old revision for diffs ($this->rev is the new rev)
31 - */
32 - public function setDiffPriorRev( Revision $refRev ) {
33 - $this->refRev = $refRev;
34 - }
35 -
36 - /*
37 - * Add on a notice inside the review box at the top
38 - * @param string $topNotice Text to
39 - */
40 - public function setTopNotice( $topNotice ) {
41 - $this->topNotice = (string)$topNotice;
42 - }
43 -
44 - /*
45 - * Set the template/file version parameters corresponding to what the user is viewing
46 - * @param string $topNotice Text to
47 - */
48 - public function setIncludeVersions( array $templateIDs, array $imageSHA1Keys ) {
49 - $this->templateIDs = $templateIDs;
50 - $this->imageSHA1Keys = $imageSHA1Keys;
51 - }
52 -
53 - /**
54 - * Generates a brief review form for a page
55 - * @return array (html string, error string or true)
56 - */
57 - public function getHtml() {
58 - global $wgOut, $wgLang, $wgParser, $wgEnableParserCache;
59 - $revId = $this->rev->getId();
60 - if ( $this->rev->isDeleted( Revision::DELETED_TEXT ) ) {
61 - return array( '', 'review_bad_oldid' ); # The revision must be valid and public
62 - }
63 - $article = $this->article; // convenience
64 -
65 - $srev = $article->getStableRev();
66 - # See if the version being displayed is flagged...
67 - if ( $revId == $article->getStable() ) {
68 - $frev = $srev; // avoid query
69 - } else {
70 - $frev = FlaggedRevision::newFromTitle( $article->getTitle(), $revId );
71 - }
72 - $oldFlags = $frev
73 - ? $frev->getTags() // existing tags
74 - : FlaggedRevs::quickTags( FR_CHECKED ); // basic tags
75 - $reviewTime = $frev ? $frev->getTimestamp() : ''; // last review of rev
76 -
77 - $priorRevId = $this->refRev ? $this->refRev->getId() : 0;
78 - # If we are reviewing updates to a page, start off with the stable revision's
79 - # flags. Otherwise, we just fill them in with the selected revision's flags.
80 - # @TODO: do we want to carry over info for other diffs?
81 - if ( $srev && $srev->getRevId() == $priorRevId ) { // diff-to-stable
82 - $flags = $srev->getTags();
83 - # Check if user is allowed to renew the stable version.
84 - # If not, then get the flags for the new revision itself.
85 - if ( !FlaggedRevs::userCanSetFlags( $this->user, $oldFlags ) ) {
86 - $flags = $oldFlags;
87 - }
88 - # Re-review button is need for template/file only review case
89 - $reviewIncludes = ( $srev->getRevId() == $revId && !$article->stableVersionIsSynced() );
90 - } else { // views
91 - $flags = $oldFlags;
92 - $reviewIncludes = false; // re-review button not needed
93 - }
94 -
95 - # Disable form for unprivileged users
96 - $disabled = array();
97 - if ( !$article->getTitle()->quickUserCan( 'review' ) ||
98 - !$article->getTitle()->quickUserCan( 'edit' ) ||
99 - !FlaggedRevs::userCanSetFlags( $this->user, $flags ) )
100 - {
101 - $disabled = array( 'disabled' => 'disabled' );
102 - }
103 -
104 - # Begin form...
105 - $reviewTitle = SpecialPage::getTitleFor( 'RevisionReview' );
106 - $action = $reviewTitle->getLocalUrl( 'action=submit' );
107 - $params = array( 'method' => 'post', 'action' => $action, 'id' => 'mw-fr-reviewform' );
108 - $form = Xml::openElement( 'form', $params );
109 - $form .= Xml::openElement( 'fieldset',
110 - array( 'class' => 'flaggedrevs_reviewform noprint' ) );
111 - # Add appropriate legend text
112 - $legendMsg = $frev ? 'revreview-reflag' : 'revreview-flag';
113 - $form .= Xml::openElement( 'legend', array( 'id' => 'mw-fr-reviewformlegend' ) );
114 - $form .= "<strong>" . wfMsgHtml( $legendMsg ) . "</strong>";
115 - $form .= Xml::closeElement( 'legend' ) . "\n";
116 - # Show explanatory text
117 - $form .= $this->topNotice;
118 - # Show possible conflict warning msg...
119 - if ( $priorRevId ) {
120 - list( $u, $ts ) =
121 - FRUserActivity::getUserReviewingDiff( $priorRevId, $this->rev->getId() );
122 - } else {
123 - list( $u, $ts ) = FRUserActivity::getUserReviewingPage( $this->rev->getPage() );
124 - }
125 - if ( $u !== null && $u != $this->user->getName() ) {
126 - $msg = $priorRevId ? 'revreview-poss-conflict-c' : 'revreview-poss-conflict-p';
127 - $form .= '<p><span class="fr-under-review">' .
128 - wfMsgExt( $msg, 'parseinline',
129 - $u, $wgLang->date( $ts, true ), $wgLang->time( $ts, true ) ) .
130 - '</span></p>';
131 - }
132 -
133 - if ( $disabled ) {
134 - $form .= Xml::openElement( 'div', array( 'class' => 'fr-rating-controls-disabled',
135 - 'id' => 'fr-rating-controls-disabled' ) );
136 - } else {
137 - $form .= Xml::openElement( 'div', array( 'class' => 'fr-rating-controls',
138 - 'id' => 'fr-rating-controls' ) );
139 - }
140 -
141 - # Add main checkboxes/selects
142 - $form .= Xml::openElement( 'span',
143 - array( 'id' => 'mw-fr-ratingselects', 'class' => 'fr-rating-options' ) );
144 - $form .= self::ratingInputs( $this->user, $flags, (bool)$disabled, (bool)$frev );
145 - $form .= Xml::closeElement( 'span' );
146 -
147 - # Get template/file version info as needed
148 - list( $templateIDs, $imageSHA1Keys ) = $this->getIncludeVersions();
149 - # Convert these into flat string params
150 - list( $templateParams, $imageParams, $fileVersion ) =
151 - RevisionReviewForm::getIncludeParams( $article, $templateIDs, $imageSHA1Keys );
152 -
153 - $form .= Xml::openElement( 'span', array( 'style' => 'white-space: nowrap;' ) );
154 - # Hide comment input if needed
155 - if ( !$disabled ) {
156 - if ( count( FlaggedRevs::getTags() ) > 1 ) {
157 - $form .= "<br />"; // Don't put too much on one line
158 - }
159 - $form .= "<span id='mw-fr-commentbox' style='clear:both'>" .
160 - Xml::inputLabel( wfMsg( 'revreview-log' ), 'wpReason', 'wpReason', 40, '',
161 - array( 'class' => 'fr-comment-box' ) ) . "&#160;&#160;&#160;</span>";
162 - }
163 - # Determine if there will be reject button
164 - $rejectId = $this->rejectRefRevId();
165 - # Add the submit buttons
166 - $form .= self::submitButtons( $rejectId, $frev, (bool)$disabled, $reviewIncludes );
167 - # Show stability log if there is anything interesting...
168 - if ( $article->isPageLocked() ) {
169 - $form .= ' ' . FlaggedRevsXML::logToggle( 'revreview-log-toggle-show' );
170 - }
171 - $form .= Xml::closeElement( 'span' );
172 - # ..add the actual stability log body here
173 - if ( $article->isPageLocked() ) {
174 - $form .= FlaggedRevsXML::stabilityLogExcerpt( $article );
175 - }
176 - $form .= Xml::closeElement( 'div' ) . "\n";
177 -
178 - # Hidden params
179 - $form .= Html::hidden( 'title', $reviewTitle->getPrefixedText() ) . "\n";
180 - $form .= Html::hidden( 'target', $article->getTitle()->getPrefixedDBKey() ) . "\n";
181 - $form .= Html::hidden( 'refid', $priorRevId ) . "\n";
182 - $form .= Html::hidden( 'oldid', $revId ) . "\n";
183 - $form .= Html::hidden( 'action', 'submit' ) . "\n";
184 - $form .= Html::hidden( 'wpEditToken', $this->user->editToken() ) . "\n";
185 - $form .= Html::hidden( 'changetime', $reviewTime,
186 - array( 'id' => 'mw-fr-input-changetime' ) ); // id for JS
187 - # Add review parameters
188 - $form .= Html::hidden( 'templateParams', $templateParams ) . "\n";
189 - $form .= Html::hidden( 'imageParams', $imageParams ) . "\n";
190 - $form .= Html::hidden( 'fileVersion', $fileVersion ) . "\n";
191 - # Special token to discourage fiddling...
192 - $checkCode = RevisionReviewForm::validationKey(
193 - $templateParams, $imageParams, $fileVersion, $revId
194 - );
195 - $form .= Html::hidden( 'validatedParams', $checkCode ) . "\n";
196 -
197 - $form .= Xml::closeElement( 'fieldset' );
198 - $form .= Xml::closeElement( 'form' );
199 -
200 - return array( $form, true /* ok */ );
201 - }
202 -
203 - /*
204 - * If the REJECT button should show then get the ID of the last good rev
205 - * @return int
206 - */
207 - protected function rejectRefRevId() {
208 - if ( $this->refRev ) {
209 - $priorId = $this->refRev->getId();
210 - if ( $priorId == $this->article->getStable() && $priorId != $this->rev->getId() ) {
211 - if ( $this->rev->getRawText() != $this->refRev->getRawText() ) {
212 - return $priorId; // left rev must be stable and right one newer
213 - }
214 - }
215 - }
216 - return 0;
217 - }
218 -
219 - /**
220 - * @param User $user
221 - * @param array $flags, selected flags
222 - * @param bool $disabled, form disabled
223 - * @param bool $reviewed, rev already reviewed
224 - * @return string
225 - * Generates a main tag inputs (checkboxes/radios/selects) for review form
226 - */
227 - protected static function ratingInputs( $user, $flags, $disabled, $reviewed ) {
228 - # Get all available tags for this page/user
229 - list( $labels, $minLevels ) = self::ratingFormTags( $user, $flags );
230 - if ( $labels === false ) {
231 - $disabled = true; // a tag is unsettable
232 - }
233 - # If there are no tags, make one checkbox to approve/unapprove
234 - if ( FlaggedRevs::binaryFlagging() ) {
235 - return '';
236 - }
237 - $items = array();
238 - # Build rating form...
239 - if ( $disabled ) {
240 - // Display the value for each tag as text
241 - foreach ( FlaggedRevs::getTags() as $quality ) {
242 - $selected = isset( $flags[$quality] ) ? $flags[$quality] : 0;
243 - $items[] = FlaggedRevs::getTagMsg( $quality ) . ": " .
244 - FlaggedRevs::getTagValueMsg( $quality, $selected );
245 - }
246 - } else {
247 - $size = count( $labels, 1 ) - count( $labels );
248 - foreach ( $labels as $quality => $levels ) {
249 - $item = '';
250 - $numLevels = count( $levels );
251 - $minLevel = $minLevels[$quality];
252 - # Determine the level selected by default
253 - if ( !empty( $flags[$quality] ) && isset( $levels[$flags[$quality]] ) ) {
254 - $selected = $flags[$quality]; // valid non-zero value
255 - } else {
256 - $selected = $minLevel;
257 - }
258 - # Show label as needed
259 - if ( !FlaggedRevs::binaryFlagging() ) {
260 - $item .= Xml::tags( 'label', array( 'for' => "wp$quality" ),
261 - FlaggedRevs::getTagMsg( $quality ) ) . ":\n";
262 - }
263 - # If the sum of qualities of all flags is above 6, use drop down boxes.
264 - # 6 is an arbitrary value choosen according to screen space and usability.
265 - if ( $size > 6 ) {
266 - $attribs = array( 'name' => "wp$quality", 'id' => "wp$quality",
267 - 'onchange' => "FlaggedRevsReview.updateRatingForm()" );
268 - $item .= Xml::openElement( 'select', $attribs ) . "\n";
269 - foreach ( $levels as $i => $name ) {
270 - $optionClass = array( 'class' => "fr-rating-option-$i" );
271 - $item .= Xml::option( FlaggedRevs::getTagMsg( $name ), $i,
272 - ( $i == $selected ), $optionClass ) . "\n";
273 - }
274 - $item .= Xml::closeElement( 'select' ) . "\n";
275 - # If there are more than two levels, current user gets radio buttons
276 - } elseif ( $numLevels > 2 ) {
277 - foreach ( $levels as $i => $name ) {
278 - $attribs = array( 'class' => "fr-rating-option-$i",
279 - 'onchange' => "FlaggedRevsReview.updateRatingForm()" );
280 - $item .= Xml::radioLabel( FlaggedRevs::getTagMsg( $name ), "wp$quality",
281 - $i, "wp$quality" . $i, ( $i == $selected ), $attribs ) . "\n";
282 - }
283 - # Otherwise make checkboxes (two levels available for current user)
284 - } else if ( $numLevels == 2 ) {
285 - $i = $minLevel;
286 - $attribs = array( 'class' => "fr-rating-option-$i",
287 - 'onchange' => "FlaggedRevsReview.updateRatingForm()" );
288 - $attribs = $attribs + array( 'value' => $i );
289 - $item .= Xml::checkLabel( wfMsg( 'revreview-' . $levels[$i] ),
290 - "wp$quality", "wp$quality", ( $selected == $i ), $attribs ) . "\n";
291 - }
292 - $items[] = $item;
293 - }
294 - }
295 - return implode( '&#160;&#160;&#160;', $items );
296 - }
297 -
298 - protected static function ratingFormTags( $user, $selected ) {
299 - $labels = array();
300 - $minLevels = array();
301 - # Build up all levels available to user
302 - foreach ( FlaggedRevs::getDimensions() as $tag => $levels ) {
303 - if ( isset( $selected[$tag] ) &&
304 - !FlaggedRevs::userCanSetTag( $user, $tag, $selected[$tag] ) )
305 - {
306 - return array( false, false ); // form will have to be disabled
307 - }
308 - $labels[$tag] = array(); // applicable tag levels
309 - $minLevels[$tag] = false; // first non-zero level number
310 - foreach ( $levels as $i => $msg ) {
311 - # Some levels may be restricted or not applicable...
312 - if ( !FlaggedRevs::userCanSetTag( $user, $tag, $i ) ) {
313 - continue; // skip this level
314 - } else if ( $i > 0 && !$minLevels[$tag] ) {
315 - $minLevels[$tag] = $i; // first non-zero level number
316 - }
317 - $labels[$tag][$i] = $msg; // set label
318 - }
319 - if ( !$minLevels[$tag] ) {
320 - return array( false, false ); // form will have to be disabled
321 - }
322 - }
323 - return array( $labels, $minLevels );
324 - }
325 -
326 - /**
327 - * Generates review form submit buttons
328 - * @param int $rejectId left rev ID for "reject" on diffs
329 - * @param FlaggedRevision $frev, the flagged revision, if any
330 - * @param bool $disabled, is the form disabled?
331 - * @param bool $reviewIncludes, force the review button to be usable?
332 - * @return string
333 - */
334 - protected static function submitButtons(
335 - $rejectId, $frev, $disabled, $reviewIncludes = false
336 - ) {
337 - $disAttrib = array( 'disabled' => 'disabled' );
338 - # ACCEPT BUTTON: accept a revision
339 - # We may want to re-review to change:
340 - # (a) notes (b) tags (c) pending template/file changes
341 - if ( FlaggedRevs::binaryFlagging() ) { // just the buttons
342 - $applicable = ( !$frev || $reviewIncludes ); // no tags/notes
343 - $needsChange = false; // no state change possible
344 - } else { // buttons + ratings
345 - $applicable = true; // tags might change
346 - $needsChange = ( $frev && !$reviewIncludes );
347 - }
348 - $s = Xml::submitButton( wfMsgHtml( 'revreview-submit-review' ),
349 - array(
350 - 'name' => 'wpApprove',
351 - 'id' => 'mw-fr-submit-accept',
352 - 'accesskey' => wfMsg( 'revreview-ak-review' ),
353 - 'title' => wfMsg( 'revreview-tt-flag' ) . ' [' .
354 - wfMsg( 'revreview-ak-review' ) . ']'
355 - ) + ( ( $disabled || !$applicable ) ? $disAttrib : array() )
356 - );
357 - # REJECT BUTTON: revert from a pending revision to the stable
358 - if ( $rejectId ) {
359 - $s .= ' ';
360 - $s .= Xml::submitButton( wfMsgHtml( 'revreview-submit-reject' ),
361 - array(
362 - 'name' => 'wpReject',
363 - 'id' => 'mw-fr-submit-reject',
364 - 'title' => wfMsg( 'revreview-tt-reject' ),
365 - ) + ( $disabled ? $disAttrib : array() )
366 - );
367 - }
368 - # UNACCEPT BUTTON: revoke a revisions acceptance
369 - # Hide if revision is not flagged
370 - $s .= ' ';
371 - $s .= Xml::submitButton( wfMsgHtml( 'revreview-submit-unreview' ),
372 - array(
373 - 'name' => 'wpUnapprove',
374 - 'id' => 'mw-fr-submit-unaccept',
375 - 'title' => wfMsg( 'revreview-tt-unflag' ),
376 - 'style' => $frev ? '' : 'display:none'
377 - ) + ( $disabled ? $disAttrib : array() )
378 - );
379 - // Disable buttons unless state changes in some cases (non-JS compatible)
380 - $s .= "<script type=\"text/javascript\">
381 - var jsReviewNeedsChange = " . (int)$needsChange . "</script>";
382 - return $s;
383 - }
384 -
385 - protected function getIncludeVersions() {
386 - # Do we need to get inclusion IDs from parser output?
387 - if ( $this->templateIDs === null || $this->imageSHA1Keys === null ) {
388 - list( $this->templateIDs, $this->imageSHA1Keys ) =
389 - RevisionReviewForm::currentIncludeVersions( $this->article, $this->rev );
390 - }
391 - return array( $this->templateIDs, $this->imageSHA1Keys );
392 - }
393 -}
Index: trunk/extensions/FlaggedRevs/presentation/RejectConfirmationFormGUI.php
@@ -1,145 +0,0 @@
2 -<?php
3 -/**
4 - * Reject confirmation review form UI
5 - */
6 -class RejectConfirmationFormGUI {
7 - protected $form, $oldRev, $newRev;
8 -
9 - public function __construct( RevisionReviewForm $form ) {
10 - $this->form = $form;
11 - $this->newRev = Revision::newFromTitle( $form->getPage(), $form->getOldId() );
12 - $this->oldRev = Revision::newFromTitle( $form->getPage(), $form->getRefId() );
13 - }
14 -
15 - /**
16 - * Get the "are you sure you want to reject these changes?" form
17 - * @return array (html string, error string or true)
18 - */
19 - public function getHtml() {
20 - global $wgLang, $wgContLang;
21 - $status = $this->form->checkTarget();
22 - if ( $status !== true ) {
23 - return array( '', $status ); // not a reviewable existing page
24 - }
25 - $oldRev = $this->oldRev; // convenience
26 - $newRev = $this->newRev; // convenience
27 - # Do not mess with archived/deleted revisions
28 - if ( !$oldRev || $newRev->isDeleted( Revision::DELETED_TEXT ) ) {
29 - return array( '', 'review_bad_oldid' );
30 - } elseif ( !$newRev || $newRev->isDeleted( Revision::DELETED_TEXT ) ) {
31 - return array( '', 'review_bad_oldid' );
32 - }
33 -
34 - $form = '<div class="plainlinks">';
35 -
36 - $dbr = wfGetDB( DB_SLAVE );
37 - $res = $dbr->select( 'revision',
38 - Revision::selectFields(),
39 - array(
40 - 'rev_page' => $oldRev->getPage(),
41 - 'rev_id > ' . $dbr->addQuotes( $oldRev->getId() ),
42 - 'rev_id <= ' . $dbr->addQuotes( $newRev->getId() )
43 - ),
44 - __METHOD__,
45 - array( 'LIMIT' => 251 ) // sanity check
46 - );
47 - if ( !$dbr->numRows( $res ) ) {
48 - return array( '', 'review_bad_oldid' );
49 - } elseif ( $dbr->numRows( $res ) > 250 ) {
50 - return array( '', 'review_reject_excessive' );
51 - }
52 -
53 - $rejectIds = $rejectAuthors = array();
54 - $contribs = SpecialPage::getTitleFor( 'Contributions' )->getPrefixedText();
55 - foreach ( $res as $row ) {
56 - $rev = new Revision( $row );
57 - $rejectIds[] = $rev->getId();
58 - $rejectAuthors[] = $rev->isDeleted( Revision::DELETED_USER )
59 - ? wfMsg( 'rev-deleted-user' )
60 - : "[[{$contribs}/{$rev->getUserText()}|{$rev->getUserText()}]]";
61 - }
62 - $rejectAuthors = array_values( array_unique( $rejectAuthors ) );
63 -
64 - // List of revisions being undone...
65 - $form .= wfMsgExt( 'revreview-reject-text-list', 'parseinline',
66 - $wgLang->formatNum( count( $rejectIds ) ) );
67 - $form .= '<ul>';
68 - // FIXME: we need a generic revision list class...this is bullshit
69 - $spRevDelete = SpecialPage::getPage( 'RevisionReview' );
70 - $spRevDelete->skin = $this->form->getUser()->getSkin(); // XXX
71 - $list = new RevDel_RevisionList( $spRevDelete, $oldRev->getTitle(), $rejectIds );
72 - for ( $list->reset(); $list->current(); $list->next() ) {
73 - $item = $list->current();
74 - if ( $item->canView() ) {
75 - $form .= $item->getHTML();
76 - }
77 - }
78 - $form .= '</ul>';
79 - if ( $newRev->isCurrent() ) {
80 - // Revision this will revert to (when reverting the top X revs)...
81 - $form .= wfMsgExt( 'revreview-reject-text-revto', 'parseinline',
82 - $oldRev->getTitle()->getPrefixedDBKey(), $oldRev->getId(),
83 - $wgLang->timeanddate( $oldRev->getTimestamp(), true )
84 - );
85 - }
86 -
87 - $comment = $this->form->getComment(); // convenience
88 - // Determine the default edit summary...
89 - $oldRevAuthor = $oldRev->isDeleted( Revision::DELETED_USER )
90 - ? wfMsg( 'rev-deleted-user' )
91 - : $oldRev->getUserText();
92 - // NOTE: *-cur msg wording not safe for (unlikely) edit auto-merge
93 - $msg = $newRev->isCurrent()
94 - ? 'revreview-reject-summary-cur'
95 - : 'revreview-reject-summary-old';
96 - $defaultSummary = wfMsgExt( $msg, array( 'parsemag', 'content' ),
97 - $wgContLang->formatNum( count( $rejectIds ) ),
98 - $wgContLang->listToText( $rejectAuthors ),
99 - $oldRev->getId(),
100 - $oldRevAuthor );
101 - // If the message is too big, then fallback to the shorter one
102 - $colonSeparator = wfMsgForContent( 'colon-separator' );
103 - $maxLen = 255 - count( $colonSeparator ) - count( $comment );
104 - if ( strlen( $defaultSummary ) > $maxLen ) {
105 - $msg = $newRev->isCurrent()
106 - ? 'revreview-reject-summary-cur-short'
107 - : 'revreview-reject-summary-old-short';
108 - $defaultSummary = wfMsgExt( $msg, array( 'parsemag', 'content' ),
109 - $wgContLang->formatNum( count( $rejectIds ) ),
110 - $oldRev->getId(),
111 - $oldRevAuthor );
112 - }
113 - // Append any review comment...
114 - if ( $comment != '' ) {
115 - if ( $defaultSummary != '' ) {
116 - $defaultSummary .= $colonSeparator;
117 - }
118 - $defaultSummary .= $comment;
119 - }
120 -
121 - $form .= '</div>';
122 -
123 - $skin = $this->form->getUser()->getSkin();
124 - $reviewTitle = SpecialPage::getTitleFor( 'RevisionReview' );
125 - $form .= Xml::openElement( 'form',
126 - array( 'method' => 'POST', 'action' => $reviewTitle->getFullUrl() ) );
127 - $form .= Html::hidden( 'action', 'reject' );
128 - $form .= Html::hidden( 'wpReject', 1 );
129 - $form .= Html::hidden( 'wpRejectConfirm', 1 );
130 - $form .= Html::hidden( 'oldid', $this->form->getOldId() );
131 - $form .= Html::hidden( 'refid', $this->form->getRefId() );
132 - $form .= Html::hidden( 'target', $oldRev->getTitle()->getPrefixedDBKey() );
133 - $form .= Html::hidden( 'wpEditToken', $this->form->getUser()->editToken() );
134 - $form .= Html::hidden( 'changetime', $newRev->getTimestamp() );
135 - $form .= Xml::inputLabel( wfMsg( 'revreview-reject-summary' ), 'wpReason',
136 - 'wpReason', 120, $defaultSummary ) . "<br />";
137 - $form .= Html::input( 'wpSubmit', wfMsg( 'revreview-reject-confirm' ), 'submit' );
138 - $form .= ' ';
139 - $form .= $skin->link( $this->form->getPage(), wfMsg( 'revreview-reject-cancel' ),
140 - array( 'onClick' => 'history.back(); return false;' ),
141 - array( 'oldid' => $this->form->getRefId(), 'diff' => $this->form->getOldId() ) );
142 - $form .= Xml::closeElement( 'form' );
143 -
144 - return array( $form, true );
145 - }
146 -}
Index: trunk/extensions/FlaggedRevs/presentation/FlaggedRevsUI.hooks.php
@@ -0,0 +1,848 @@
 2+<?php
 3+/**
 4+ * Class containing hooked functions for a FlaggedRevs environment
 5+ */
 6+class FlaggedRevsUIHooks {
 7+ /*
 8+ * Register FlaggedRevs special pages as needed.
 9+ * Also sets $wgSpecialPages just to be consistent.
 10+ */
 11+ public static function defineSpecialPages( array &$list ) {
 12+ global $wgSpecialPages, $wgUseTagFilter;
 13+ // Show special pages only if FlaggedRevs is enabled on some namespaces
 14+ if ( !FlaggedRevs::getReviewNamespaces() ) {
 15+ return true;
 16+ }
 17+ $list['RevisionReview'] = $wgSpecialPages['RevisionReview'] = 'RevisionReview';
 18+ $list['ReviewedVersions'] = $wgSpecialPages['ReviewedVersions'] = 'ReviewedVersions';
 19+ $list['PendingChanges'] = $wgSpecialPages['PendingChanges'] = 'PendingChanges';
 20+ // Show tag filtered pending edit page if there are tags
 21+ if ( $wgUseTagFilter && ChangeTags::listDefinedTags() ) {
 22+ $list['ProblemChanges'] = $wgSpecialPages['ProblemChanges'] = 'ProblemChanges';
 23+ }
 24+ if ( !FlaggedRevs::useOnlyIfProtected() ) {
 25+ $list['ReviewedPages'] = $wgSpecialPages['ReviewedPages'] = 'ReviewedPages';
 26+ $list['UnreviewedPages'] = $wgSpecialPages['UnreviewedPages'] = 'UnreviewedPages';
 27+ }
 28+ $list['QualityOversight'] = $wgSpecialPages['QualityOversight'] = 'QualityOversight';
 29+ $list['ValidationStatistics'] = $wgSpecialPages['ValidationStatistics'] = 'ValidationStatistics';
 30+ // Protect levels define allowed stability settings
 31+ if ( FlaggedRevs::useProtectionLevels() ) {
 32+ $list['StablePages'] = $wgSpecialPages['StablePages'] = 'StablePages';
 33+ } else {
 34+ $list['ConfiguredPages'] = $wgSpecialPages['ConfiguredPages'] = 'ConfiguredPages';
 35+ $list['Stabilization'] = $wgSpecialPages['Stabilization'] = 'Stabilization';
 36+ }
 37+ return true;
 38+ }
 39+
 40+ /**
 41+ * Add FlaggedRevs css/js.
 42+ */
 43+ protected static function injectStyleAndJS() {
 44+ global $wgOut, $wgUser;
 45+ static $loadedModules = false;
 46+ if ( $loadedModules ) {
 47+ return true; // don't double-load
 48+ }
 49+ $loadedModules = true;
 50+ $fa = FlaggedPageView::globalArticleInstance();
 51+ # Try to only add to relevant pages
 52+ if ( !$fa || !$fa->isReviewable() ) {
 53+ return true;
 54+ }
 55+ # Add main CSS & JS files
 56+ $wgOut->addModuleStyles( 'ext.flaggedRevs.basic' );
 57+ $wgOut->addModules( 'ext.flaggedRevs.advanced' );
 58+ # Add review form JS for reviewers
 59+ if ( $wgUser->isAllowed( 'review' ) ) {
 60+ $wgOut->addModules( 'ext.flaggedRevs.review' );
 61+ }
 62+ return true;
 63+ }
 64+
 65+ public static function injectGlobalJSVars( array &$globalVars ) {
 66+ # Get the review tags on this wiki
 67+ $rTags = FlaggedRevs::getJSTagParams();
 68+ $globalVars['wgFlaggedRevsParams'] = $rTags;
 69+ # Get page-specific meta-data
 70+ $fa = FlaggedPageView::globalArticleInstance();
 71+ # Try to only add to relevant pages
 72+ if ( $fa && $fa->isReviewable() ) {
 73+ $frev = $fa->getStableRev();
 74+ $stableId = $frev ? $frev->getRevId() : 0;
 75+ } else {
 76+ $stableId = null;
 77+ }
 78+ $globalVars['wgStableRevisionId'] = $stableId;
 79+ $revisionContents = (object) array(
 80+ 'error' => wfMsgHtml( 'revcontents-error' ),
 81+ 'waiting' => wfMsgHtml( 'revcontents-waiting' )
 82+ );
 83+ $globalVars['wgRevContents'] = $revisionContents;
 84+ return true;
 85+ }
 86+
 87+ /**
 88+ * Add FlaggedRevs css for relevant special pages.
 89+ * @param OutputPage $out
 90+ */
 91+ protected static function injectStyleForSpecial( &$out ) {
 92+ $title = $out->getTitle();
 93+ if ( $title->getNamespace() !== NS_SPECIAL ) {
 94+ return true;
 95+ }
 96+ $spPages = array( 'UnreviewedPages', 'PendingChanges', 'ProblemChanges',
 97+ 'Watchlist', 'Recentchanges', 'Contributions', 'Recentchangeslinked' );
 98+ foreach ( $spPages as $key ) {
 99+ if ( $title->isSpecial( $key ) ) {
 100+ $out->addModuleStyles( 'ext.flaggedRevs.basic' ); // CSS only
 101+ break;
 102+ }
 103+ }
 104+ return true;
 105+ }
 106+
 107+ /*
 108+ * Add tag notice, CSS/JS, and set robots policy
 109+ */
 110+ public static function onBeforePageDisplay( &$out, &$skin ) {
 111+ if ( $out->isArticleRelated() ) {
 112+ $view = FlaggedPageView::singleton();
 113+ $view->displayTag(); // show notice bar/icon in subtitle
 114+ $view->setRobotPolicy(); // set indexing policy
 115+ self::injectStyleAndJS(); // full CSS/JS
 116+ } else {
 117+ self::maybeAddBacklogNotice( $out ); // RC/Watchlist notice
 118+ self::injectStyleForSpecial( $out ); // try special page CSS
 119+ }
 120+ return true;
 121+ }
 122+
 123+ public static function onMediaWikiPerformAction(
 124+ $output, $article, Title $title, $user, $request
 125+ ) {
 126+ $fa = FlaggedPage::getTitleInstance( $title );
 127+ self::maybeMarkUnderReview( $fa, $request );
 128+ return true;
 129+ }
 130+
 131+ // Mark when an unreviewed page is being reviewed
 132+ protected static function maybeMarkUnderReview( FlaggedPage $fa, WebRequest $request ) {
 133+ global $wgUser;
 134+ if ( !$request->getInt( 'reviewing' ) && !$request->getInt( 'rcid' ) ) {
 135+ return true; // not implied by URL
 136+ }
 137+ # Set a key to note when someone is reviewing this.
 138+ # NOTE: diff-to-stable views already handled elsewhere.
 139+ if ( $fa->isReviewable() && !$fa->getStable() // not reviewed yet
 140+ && $fa->getTitle()->userCan( 'review' ) )
 141+ {
 142+ FRUserActivity::setUserReviewingPage( $wgUser, $fa->getID() );
 143+ }
 144+ return true;
 145+ }
 146+
 147+ /** Add user preferences */
 148+ public static function onGetPreferences( $user, array &$preferences ) {
 149+ // Box or bar UI
 150+ $preferences['flaggedrevssimpleui'] =
 151+ array(
 152+ 'type' => 'radio',
 153+ 'section' => 'flaggedrevs/flaggedrevs-ui',
 154+ 'label-message' => 'flaggedrevs-pref-UI',
 155+ 'options' => array(
 156+ wfMsg( 'flaggedrevs-pref-UI-0' ) => 0,
 157+ wfMsg( 'flaggedrevs-pref-UI-1' ) => 1,
 158+ ),
 159+ );
 160+ // Default versions...
 161+ $preferences['flaggedrevsstable'] =
 162+ array(
 163+ 'type' => 'toggle',
 164+ 'section' => 'flaggedrevs/flaggedrevs-ui',
 165+ 'label-message' => 'flaggedrevs-prefs-stable',
 166+ );
 167+ // Review-related rights...
 168+ if ( $user->isAllowed( 'review' ) ) {
 169+ // Watching reviewed pages
 170+ $preferences['flaggedrevswatch'] =
 171+ array(
 172+ 'type' => 'toggle',
 173+ 'section' => 'watchlist/advancedwatchlist',
 174+ 'label-message' => 'flaggedrevs-prefs-watch',
 175+ );
 176+ // Diff-to-stable on edit
 177+ $preferences['flaggedrevseditdiffs'] =
 178+ array(
 179+ 'type' => 'toggle',
 180+ 'section' => 'editing/advancedediting',
 181+ 'label-message' => 'flaggedrevs-prefs-editdiffs',
 182+ );
 183+ // Diff-to-stable on draft view
 184+ $preferences['flaggedrevsviewdiffs'] =
 185+ array(
 186+ 'type' => 'toggle',
 187+ 'section' => 'flaggedrevs/flaggedrevs-ui',
 188+ 'label-message' => 'flaggedrevs-prefs-viewdiffs',
 189+ );
 190+ }
 191+ return true;
 192+ }
 193+
 194+ public static function logLineLinks(
 195+ $type, $action, $title, $params, &$comment, &$rv, $ts
 196+ ) {
 197+ if ( !$title ) {
 198+ return true; // sanity check
 199+ }
 200+ // Stability log
 201+ if ( $type == 'stable' && FlaggedRevsLog::isStabilityAction( $action ) ) {
 202+ $rv .= FlaggedRevsLogView::stabilityLogLinks( $title, $ts, $params );
 203+ // Review log
 204+ } elseif ( $type == 'review' && FlaggedRevsLog::isReviewAction( $action ) ) {
 205+ $rv .= FlaggedRevsLogView::reviewLogLinks( $action, $title, $params );
 206+ }
 207+ return true;
 208+ }
 209+
 210+ public static function onImagePageFindFile( $imagePage, &$normalFile, &$displayFile ) {
 211+ $view = FlaggedPageView::singleton();
 212+ $view->imagePageFindFile( $normalFile, $displayFile );
 213+ return true;
 214+ }
 215+
 216+ // MonoBook et al: $contentActions is all the tabs
 217+ // Vector et al: $contentActions is all the action tabs...unused
 218+ public static function onSkinTemplateTabs( Skin $skin, array &$contentActions ) {
 219+ if ( $skin instanceof SkinVector ) {
 220+ // *sigh*...skip, dealt with in setNavigation()
 221+ return true;
 222+ }
 223+ // Note: $wgArticle sometimes not set here
 224+ if ( FlaggedPageView::globalArticleInstance() != null ) {
 225+ $view = FlaggedPageView::singleton();
 226+ $view->setActionTabs( $skin, $contentActions );
 227+ $view->setViewTabs( $skin, $contentActions, 'flat' );
 228+ }
 229+ return true;
 230+ }
 231+
 232+ // Vector et al: $links is all the tabs (2 levels)
 233+ public static function onSkinTemplateNavigation( Skin $skin, array &$links ) {
 234+ // Note: $wgArticle sometimes not set here
 235+ if ( FlaggedPageView::globalArticleInstance() != null ) {
 236+ $view = FlaggedPageView::singleton();
 237+ $view->setActionTabs( $skin, $links['actions'] );
 238+ $view->setViewTabs( $skin, $links['views'], 'nav' );
 239+ }
 240+ return true;
 241+ }
 242+
 243+ public static function onArticleViewHeader( &$article, &$outputDone, &$useParserCache ) {
 244+ $view = FlaggedPageView::singleton();
 245+ $view->addStableLink( $outputDone, $useParserCache );
 246+ $view->setPageContent( $outputDone, $useParserCache );
 247+ return true;
 248+ }
 249+
 250+ public static function overrideRedirect(
 251+ Title $title, WebRequest $request, &$ignoreRedirect, &$target, Article &$article
 252+ ) {
 253+ global $wgMemc, $wgParserCacheExpireTime;
 254+ $fa = FlaggedPage::getTitleInstance( $title ); // on $wgTitle
 255+ if ( !$fa->isReviewable() ) {
 256+ return true; // nothing to do
 257+ }
 258+ # Viewing an old reviewed version...
 259+ if ( $request->getVal( 'stableid' ) ) {
 260+ $ignoreRedirect = true; // don't redirect (same as ?oldid=x)
 261+ return true;
 262+ }
 263+ $srev = $fa->getStableRev();
 264+ $view = FlaggedPageView::singleton();
 265+ # Check if we are viewing an unsynced stable version...
 266+ if ( $srev && $view->showingStable() && $srev->getRevId() != $article->getLatest() ) {
 267+ # Check the stable redirect properties from the cache...
 268+ $key = wfMemcKey( 'flaggedrevs', 'overrideRedirect', $article->getId() );
 269+ $tuple = FlaggedRevs::getMemcValue( $wgMemc->get( $key ), $article );
 270+ if ( is_array( $tuple ) ) { // cache hit
 271+ list( $ignoreRedirect, $target ) = $tuple;
 272+ } else { // cache miss; fetch the stable rev text...
 273+ $text = $srev->getRevText();
 274+ $redirect = $fa->getRedirectURL( Title::newFromRedirectRecurse( $text ) );
 275+ if ( $redirect ) {
 276+ $target = $redirect; // use stable redirect
 277+ } else {
 278+ $ignoreRedirect = true; // make MW skip redirection
 279+ }
 280+ $data = FlaggedRevs::makeMemcObj( array( $ignoreRedirect, $target ) );
 281+ $wgMemc->set( $key, $data, $wgParserCacheExpireTime ); // cache results
 282+ }
 283+ $clearEnvironment = (bool)$target;
 284+ # Check if the we are viewing a draft or synced stable version...
 285+ } else {
 286+ # In both cases, we can just let MW use followRedirect()
 287+ # on the draft as normal, avoiding any page text hits.
 288+ $clearEnvironment = $article->isRedirect();
 289+ }
 290+ # Environment (e.g. $wgTitle) will change in MediaWiki::initializeArticle
 291+ if ( $clearEnvironment ) $view->clear();
 292+ return true;
 293+ }
 294+
 295+ public static function addToEditView( &$editPage ) {
 296+ $view = FlaggedPageView::singleton();
 297+ $view->addToEditView( $editPage );
 298+ return true;
 299+ }
 300+
 301+ public static function onBeforeEditButtons( &$editPage, &$buttons ) {
 302+ $view = FlaggedPageView::singleton();
 303+ $view->changeSaveButton( $editPage, $buttons );
 304+ return true;
 305+ }
 306+
 307+ public static function onNoSuchSection( &$editPage, &$s ) {
 308+ $view = FlaggedPageView::singleton();
 309+ $view->addToNoSuchSection( $editPage, $s );
 310+ return true;
 311+ }
 312+
 313+ public static function addToHistView( &$article ) {
 314+ $view = FlaggedPageView::singleton();
 315+ $view->addToHistView();
 316+ return true;
 317+ }
 318+
 319+ public static function onCategoryPageView( &$category ) {
 320+ $view = FlaggedPageView::singleton();
 321+ $view->addToCategoryView();
 322+ return true;
 323+ }
 324+
 325+ public static function onSkinAfterContent( &$data ) {
 326+ global $wgOut;
 327+ if ( $wgOut->isArticleRelated()
 328+ && FlaggedPageView::globalArticleInstance() != null )
 329+ {
 330+ $view = FlaggedPageView::singleton();
 331+ $view->addReviewNotes( $data );
 332+ $view->addReviewForm( $data );
 333+ $view->addVisibilityLink( $data );
 334+ }
 335+ return true;
 336+ }
 337+
 338+ public static function addToHistQuery( HistoryPager $pager, array &$queryInfo ) {
 339+ $flaggedArticle = FlaggedPage::getArticleInstance( $pager->getArticle() );
 340+ # Non-content pages cannot be validated. Stable version must exist.
 341+ if ( $flaggedArticle->isReviewable() && $flaggedArticle->getStableRev() ) {
 342+ # Highlight flaggedrevs
 343+ $queryInfo['tables'][] = 'flaggedrevs';
 344+ $queryInfo['fields'][] = 'fr_quality';
 345+ $queryInfo['fields'][] = 'fr_user';
 346+ $queryInfo['fields'][] = 'fr_flags';
 347+ $queryInfo['join_conds']['flaggedrevs'] = array( 'LEFT JOIN',
 348+ "fr_page_id = rev_page AND fr_rev_id = rev_id" );
 349+ # Find reviewer name. Sanity check that no extensions added a `user` query.
 350+ if ( !in_array( 'user', $queryInfo['tables'] ) ) {
 351+ $queryInfo['tables'][] = 'user';
 352+ $queryInfo['fields'][] = 'user_name AS reviewer';
 353+ $queryInfo['join_conds']['user'] = array( 'LEFT JOIN', "user_id = fr_user" );
 354+ }
 355+ }
 356+ return true;
 357+ }
 358+
 359+ public static function addToFileHistQuery(
 360+ File $file, array &$tables, array &$fields, &$conds, array &$opts, array &$join_conds
 361+ ) {
 362+ if ( !$file->isLocal() ) {
 363+ return true; // local files only
 364+ }
 365+ $flaggedArticle = FlaggedPage::getTitleInstance( $file->getTitle() );
 366+ # Non-content pages cannot be validated. Stable version must exist.
 367+ if ( $flaggedArticle->isReviewable() && $flaggedArticle->getStableRev() ) {
 368+ $tables[] = 'flaggedrevs';
 369+ $fields[] = 'MAX(fr_quality) AS fr_quality';
 370+ # Avoid duplicate rows due to multiple revs with the same sha-1 key
 371+
 372+ # This is a stupid hack to get all the field names in our GROUP BY
 373+ # clause. Postgres yells at you for not including all of the selected
 374+ # columns, so grab the full list, unset the two we actually want to
 375+ # order by, then append the rest of them to our two. It would be
 376+ # REALLY nice if we handled this automagically in makeSelectOptions()
 377+ # or something *sigh*
 378+ $groupBy = OldLocalFile::selectFields();
 379+ unset( $groupBy[ array_search( 'oi_name', $groupBy ) ] );
 380+ unset( $groupBy[ array_search( 'oi_timestamp', $groupBy ) ] );
 381+ $opts['GROUP BY'] = 'oi_name,oi_timestamp,' . implode( ',', $groupBy );
 382+
 383+ $join_conds['flaggedrevs'] = array( 'LEFT JOIN',
 384+ 'oi_sha1 = fr_img_sha1 AND oi_timestamp = fr_img_timestamp' );
 385+ }
 386+ return true;
 387+ }
 388+
 389+ public static function addToContribsQuery( $pager, array &$queryInfo ) {
 390+ # Highlight flaggedrevs
 391+ $queryInfo['tables'][] = 'flaggedrevs';
 392+ $queryInfo['fields'][] = 'fr_quality';
 393+ $queryInfo['join_conds']['flaggedrevs'] = array( 'LEFT JOIN',
 394+ "fr_page_id = rev_page AND fr_rev_id = rev_id" );
 395+ # Highlight unchecked content
 396+ $queryInfo['tables'][] = 'flaggedpages';
 397+ $queryInfo['fields'][] = 'fp_stable';
 398+ $queryInfo['fields'][] = 'fp_pending_since';
 399+ $queryInfo['join_conds']['flaggedpages'] = array( 'LEFT JOIN', "fp_page_id = rev_page" );
 400+ return true;
 401+ }
 402+
 403+ public static function addToRCQuery(
 404+ &$conds, array &$tables, array &$join_conds, $opts, &$query_opts, &$select
 405+ ) {
 406+ $tables[] = 'flaggedpages';
 407+ $join_conds['flaggedpages'] = array( 'LEFT JOIN', 'fp_page_id = rc_cur_id' );
 408+ if ( is_array( $select ) ) { // RCL
 409+ $select[] = 'fp_stable';
 410+ $select[] = 'fp_pending_since';
 411+ }
 412+ return true;
 413+ }
 414+
 415+ public static function addToWatchlistQuery(
 416+ &$conds, array &$tables, array &$join_conds, array &$fields
 417+ ) {
 418+ global $wgUser;
 419+ if ( $wgUser->isAllowed( 'review' ) ) {
 420+ $fields[] = 'fp_stable';
 421+ $fields[] = 'fp_pending_since';
 422+ $tables[] = 'flaggedpages';
 423+ $join_conds['flaggedpages'] = array( 'LEFT JOIN', 'fp_page_id = rc_cur_id' );
 424+ }
 425+ return true;
 426+ }
 427+
 428+ public static function addToHistLine( HistoryPager $history, $row, &$s, &$liClasses ) {
 429+ $fa = FlaggedPage::getArticleInstance( $history->getArticle() );
 430+ if ( !$fa->isReviewable() ) {
 431+ return true; // nothing to do here
 432+ }
 433+ # Fetch and process cache the stable revision
 434+ if ( !isset( $history->fr_stableRevId ) ) {
 435+ $srev = $fa->getStableRev();
 436+ $history->fr_stableRevId = $srev ? $srev->getRevId() : null;
 437+ $history->fr_stableRevUTS = $srev ? // bug 15515
 438+ wfTimestamp( TS_UNIX, $srev->getRevTimestamp() ) : null;
 439+ $history->fr_pendingRevs = false;
 440+ }
 441+ if ( !$history->fr_stableRevId ) {
 442+ return true; // nothing to do here
 443+ }
 444+ $title = $history->getArticle()->getTitle();
 445+ $revId = (int)$row->rev_id;
 446+ // Pending revision: highlight and add diff link
 447+ $link = $class = '';
 448+ if ( wfTimestamp( TS_UNIX, $row->rev_timestamp ) > $history->fr_stableRevUTS ) {
 449+ $class = 'flaggedrevs-pending';
 450+ $link = wfMsgExt( 'revreview-hist-pending-difflink', 'parseinline',
 451+ $title->getPrefixedText(), $history->fr_stableRevId, $revId );
 452+ $link = '<span class="plainlinks">' . $link . '</span>';
 453+ $history->fr_pendingRevs = true; // pending rev shown above stable
 454+ // Reviewed revision: highlight and add link
 455+ } elseif ( isset( $row->fr_quality ) ) {
 456+ if ( !( $row->rev_deleted & Revision::DELETED_TEXT ) ) {
 457+ # Add link to stable version of *this* rev, if any
 458+ list( $link, $class ) = self::markHistoryRow( $title, $row );
 459+ # Space out and demark the stable revision
 460+ if ( $revId == $history->fr_stableRevId && $history->fr_pendingRevs ) {
 461+ $liClasses[] = 'fr-hist-stable-margin';
 462+ }
 463+ }
 464+ }
 465+ # Style the row as needed
 466+ if ( $class ) $s = "<span class='$class'>$s</span>";
 467+ # Add stable old version link
 468+ if ( $link ) $s .= " <small>$link</small>";
 469+ return true;
 470+ }
 471+
 472+ /**
 473+ * Make stable version link and return the css
 474+ * @param Title $title
 475+ * @param Row $row, from history page
 476+ * @return array (string,string)
 477+ */
 478+ protected static function markHistoryRow( Title $title, $row ) {
 479+ if ( !isset( $row->fr_quality ) ) {
 480+ return array( "", "" ); // not reviewed
 481+ }
 482+ $liCss = FlaggedRevsXML::getQualityColor( $row->fr_quality );
 483+ $flags = explode( ',', $row->fr_flags );
 484+ if ( in_array( 'auto', $flags ) ) {
 485+ $msg = ( $row->fr_quality >= 1 )
 486+ ? 'revreview-hist-quality-auto'
 487+ : 'revreview-hist-basic-auto';
 488+ $css = ( $row->fr_quality >= 1 )
 489+ ? 'fr-hist-quality-auto'
 490+ : 'fr-hist-basic-auto';
 491+ } else {
 492+ $msg = ( $row->fr_quality >= 1 )
 493+ ? 'revreview-hist-quality-user'
 494+ : 'revreview-hist-basic-user';
 495+ $css = ( $row->fr_quality >= 1 )
 496+ ? 'fr-hist-quality-user'
 497+ : 'fr-hist-basic-user';
 498+ }
 499+ $name = isset( $row->reviewer ) ?
 500+ $row->reviewer : User::whoIs( $row->fr_user );
 501+ $link = wfMsgExt( $msg, 'parseinline', $title->getPrefixedDBkey(), $row->rev_id, $name );
 502+ $link = "<span class='$css plainlinks'>[$link]</span>";
 503+ return array( $link, $liCss );
 504+ }
 505+
 506+ public static function addToFileHistLine( $hist, File $file, &$s, &$rowClass ) {
 507+ if ( !$file->isVisible() ) {
 508+ return true; // Don't bother showing notice for deleted revs
 509+ }
 510+ # Quality level for old versions selected all at once.
 511+ # Commons queries cannot be done all at once...
 512+ if ( !$file->isOld() || !$file->isLocal() ) {
 513+ $dbr = wfGetDB( DB_SLAVE );
 514+ $quality = $dbr->selectField( 'flaggedrevs', 'fr_quality',
 515+ array( 'fr_img_sha1' => $file->getSha1(),
 516+ 'fr_img_timestamp' => $dbr->timestamp( $file->getTimestamp() ) ),
 517+ __METHOD__
 518+ );
 519+ } else {
 520+ $quality = is_null( $file->quality ) ? false : $file->quality;
 521+ }
 522+ # If reviewed, class the line
 523+ if ( $quality !== false ) {
 524+ $rowClass = FlaggedRevsXML::getQualityColor( $quality );
 525+ }
 526+ return true;
 527+ }
 528+
 529+ public static function addToContribsLine( $contribs, &$ret, $row ) {
 530+ $namespaces = FlaggedRevs::getReviewNamespaces();
 531+ if ( !in_array( $row->page_namespace, $namespaces ) ) {
 532+ // do nothing
 533+ } elseif ( isset( $row->fr_quality ) ) {
 534+ $ret = '<span class="' . FlaggedRevsXML::getQualityColor( $row->fr_quality ) .
 535+ '">' . $ret . '</span>';
 536+ } elseif ( isset( $row->fp_pending_since )
 537+ && $row->rev_timestamp >= $row->fp_pending_since ) // bug 15515
 538+ {
 539+ $ret = '<span class="flaggedrevs-pending">' . $ret . '</span>';
 540+ } elseif ( !isset( $row->fp_stable ) ) {
 541+ $ret = '<span class="flaggedrevs-unreviewed">' . $ret . '</span>';
 542+ }
 543+ return true;
 544+ }
 545+
 546+ public static function addToChangeListLine( &$list, &$articlelink, &$s, RecentChange &$rc ) {
 547+ global $wgUser;
 548+ $title = $rc->getTitle(); // convenience
 549+ if ( !FlaggedRevs::inReviewNamespace( $title )
 550+ || empty( $rc->mAttribs['rc_this_oldid'] ) // rev, not log
 551+ || !array_key_exists( 'fp_stable', $rc->mAttribs ) )
 552+ {
 553+ return true; // confirm that page is in reviewable namespace
 554+ }
 555+ $rlink = '';
 556+ // page is not reviewed
 557+ if ( $rc->mAttribs['fp_stable'] == null ) {
 558+ // Is this a config were pages start off reviewable?
 559+ // Hide notice from non-reviewers due to vandalism concerns (bug 24002).
 560+ if ( !FlaggedRevs::useOnlyIfProtected() && $wgUser->isAllowed( 'review' ) ) {
 561+ $rlink = wfMsgHtml( 'revreview-unreviewedpage' );
 562+ $css = 'flaggedrevs-unreviewed';
 563+ }
 564+ // page is reviewed and has pending edits (use timestamps; bug 15515)
 565+ } elseif ( isset( $rc->mAttribs['fp_pending_since'] ) &&
 566+ $rc->mAttribs['rc_timestamp'] >= $rc->mAttribs['fp_pending_since'] )
 567+ {
 568+ $rlink = $list->skin->link(
 569+ $title,
 570+ wfMsgHtml( 'revreview-reviewlink' ),
 571+ array( 'title' => wfMsg( 'revreview-reviewlink-title' ) ),
 572+ array( 'oldid' => $rc->mAttribs['fp_stable'], 'diff' => 'cur' )
 573+ );
 574+ $css = 'flaggedrevs-pending';
 575+ }
 576+ if ( $rlink != '' ) {
 577+ $articlelink .= " <span class=\"mw-fr-reviewlink $css\">[$rlink]</span>";
 578+ }
 579+ return true;
 580+ }
 581+
 582+ public static function injectPostEditURLParams( $article, &$sectionAnchor, &$extraQuery ) {
 583+ // Note: $wgArticle sometimes not set here
 584+ if ( FlaggedPageView::globalArticleInstance() != null ) {
 585+ $view = FlaggedPageView::singleton();
 586+ $view->injectPostEditURLParams( $sectionAnchor, $extraQuery );
 587+ }
 588+ return true;
 589+ }
 590+
 591+ // diff=review param (bug 16923)
 592+ public static function checkDiffUrl( $titleObj, &$mOldid, &$mNewid, $old, $new ) {
 593+ if ( $new === 'review' && isset( $titleObj ) ) {
 594+ $frev = FlaggedRevision::newFromStable( $titleObj );
 595+ if ( $frev ) {
 596+ $mOldid = $frev->getRevId(); // stable
 597+ $mNewid = 0; // cur
 598+ }
 599+ }
 600+ return true;
 601+ }
 602+
 603+ public static function onDiffViewHeader( $diff, $oldRev, $newRev ) {
 604+ self::injectStyleAndJS();
 605+ $view = FlaggedPageView::singleton();
 606+ $view->setViewFlags( $diff, $oldRev, $newRev );
 607+ $view->addToDiffView( $diff, $oldRev, $newRev );
 608+ return true;
 609+ }
 610+
 611+ /*
 612+ * If an article is reviewable, get custom article contents from the FlaggedPageView
 613+ */
 614+ public static function onArticleContentOnDiff( $diffEngine, $out ) {
 615+ $fa = FlaggedPage::getTitleInstance( $out->getTitle() );
 616+ if ( !$fa->isReviewable() ) {
 617+ return true; // nothing to do
 618+ }
 619+ $view = FlaggedPageView::singleton();
 620+ $view->addCustomContentHtml( $out, $diffEngine->getNewid() );
 621+ return false;
 622+ }
 623+
 624+ public static function addRevisionIDField( $editPage, $out ) {
 625+ $view = FlaggedPageView::singleton();
 626+ $view->addRevisionIDField( $editPage, $out );
 627+ return true;
 628+ }
 629+
 630+ public static function addReviewCheck( $editPage, &$checkboxes, &$tabindex ) {
 631+ $view = FlaggedPageView::singleton();
 632+ $view->addReviewCheck( $editPage, $checkboxes, $tabindex );
 633+ return true;
 634+ }
 635+
 636+ protected static function maybeAddBacklogNotice( OutputPage &$out ) {
 637+ global $wgUser;
 638+ if ( !$wgUser->isAllowed( 'review' ) ) {
 639+ return true; // not relevant to user
 640+ }
 641+ $namespaces = FlaggedRevs::getReviewNamespaces();
 642+ $watchlist = SpecialPage::getTitleFor( 'Watchlist' );
 643+ # Add notice to watchlist about pending changes...
 644+ if ( $out->getTitle()->equals( $watchlist ) && $namespaces ) {
 645+ $dbr = wfGetDB( DB_SLAVE, 'watchlist' ); // consistency with watchlist
 646+ $watchedOutdated = (bool)$dbr->selectField(
 647+ array( 'watchlist', 'page', 'flaggedpages' ),
 648+ '1', // existence
 649+ array( 'wl_user' => $wgUser->getId(), // this user
 650+ 'wl_namespace' => $namespaces, // reviewable
 651+ 'wl_namespace = page_namespace',
 652+ 'wl_title = page_title',
 653+ 'fp_page_id = page_id',
 654+ 'fp_pending_since IS NOT NULL', // edits pending
 655+ ), __METHOD__
 656+ );
 657+ # Give a notice if pages on the users's wachlist have pending edits
 658+ if ( $watchedOutdated ) {
 659+ $css = 'plainlinks fr-watchlist-pending-notice';
 660+ $out->prependHTML( "<div id='mw-fr-watchlist-pending-notice' class='$css'>" .
 661+ wfMsgExt( 'flaggedrevs-watched-pending', 'parseinline' ) . "</div>" );
 662+ }
 663+ }
 664+ return true;
 665+ }
 666+
 667+ // Add selector of review "protection" options
 668+ // Code stolen from Stabilization (which was stolen from ProtectionForm)
 669+ public static function onProtectionForm( Article $article, &$output ) {
 670+ global $wgUser, $wgOut, $wgRequest, $wgLang;
 671+ if ( !$article->exists() ) {
 672+ return true; // nothing to do
 673+ } elseif ( !FlaggedRevs::inReviewNamespace( $article->getTitle() ) ) {
 674+ return true; // not a reviewable page
 675+ }
 676+ $form = new PageStabilityProtectForm( $wgUser );
 677+ $form->setPage( $article->getTitle() );
 678+ # Can the user actually do anything?
 679+ $isAllowed = $form->isAllowed();
 680+ $disabledAttrib = $isAllowed ?
 681+ array() : array( 'disabled' => 'disabled' );
 682+
 683+ # Get the current config/expiry
 684+ $config = FlaggedPageConfig::getStabilitySettings( $article->getTitle(), FR_MASTER );
 685+ $oldExpirySelect = ( $config['expiry'] == 'infinity' ) ? 'infinite' : 'existing';
 686+
 687+ # Load requested restriction level, default to current level...
 688+ $restriction = $wgRequest->getVal( 'mwStabilityLevel',
 689+ FlaggedPageConfig::getProtectionLevel( $config ) );
 690+ # Load the requested expiry time (dropdown)
 691+ $expirySelect = $wgRequest->getVal( 'mwStabilizeExpirySelection', $oldExpirySelect );
 692+ # Load the requested expiry time (field)
 693+ $expiryOther = $wgRequest->getVal( 'mwStabilizeExpiryOther', '' );
 694+ if ( $expiryOther != '' ) $expirySelect = 'othertime'; // mutual exclusion
 695+
 696+ # Add an extra row to the protection fieldset tables.
 697+ # Includes restriction dropdown and expiry dropdown & field.
 698+ $output .= "<tr><td>";
 699+ $output .= Xml::openElement( 'fieldset' );
 700+ $legendMsg = wfMsgExt( 'flaggedrevs-protect-legend', 'parseinline' );
 701+ $output .= "<legend>{$legendMsg}</legend>";
 702+ # Add a "no restrictions" level
 703+ $effectiveLevels = FlaggedRevs::getRestrictionLevels();
 704+ array_unshift( $effectiveLevels, "none" );
 705+ # Show all restriction levels in a <select>...
 706+ $attribs = array(
 707+ 'id' => 'mwStabilityLevel',
 708+ 'name' => 'mwStabilityLevel',
 709+ 'size' => count( $effectiveLevels ),
 710+ ) + $disabledAttrib;
 711+ $output .= Xml::openElement( 'select', $attribs );
 712+ foreach ( $effectiveLevels as $limit ) {
 713+ if ( $limit == 'none' ) {
 714+ $label = wfMsg( 'flaggedrevs-protect-none' );
 715+ } else {
 716+ $label = wfMsg( 'flaggedrevs-protect-' . $limit );
 717+ }
 718+ // Default to the key itself if no UI message
 719+ if ( wfEmptyMsg( 'flaggedrevs-protect-' . $limit, $label ) ) {
 720+ $label = 'flaggedrevs-protect-' . $limit;
 721+ }
 722+ $output .= Xml::option( $label, $limit, $limit == $restriction );
 723+ }
 724+ $output .= Xml::closeElement( 'select' );
 725+
 726+ # Get expiry dropdown <select>...
 727+ $scExpiryOptions = wfMsgForContent( 'protect-expiry-options' );
 728+ $showProtectOptions = ( $scExpiryOptions !== '-' && $isAllowed );
 729+ # Add the current expiry as an option
 730+ $expiryFormOptions = '';
 731+ if ( $config['expiry'] != 'infinity' ) {
 732+ $timestamp = $wgLang->timeanddate( $config['expiry'] );
 733+ $d = $wgLang->date( $config['expiry'] );
 734+ $t = $wgLang->time( $config['expiry'] );
 735+ $expiryFormOptions .=
 736+ Xml::option(
 737+ wfMsg( 'protect-existing-expiry', $timestamp, $d, $t ),
 738+ 'existing',
 739+ $expirySelect == 'existing'
 740+ ) . "\n";
 741+ }
 742+ $expiryFormOptions .= Xml::option( wfMsg( 'protect-othertime-op' ), 'othertime' ) . "\n";
 743+ # Add custom dropdown levels (from MediaWiki message)
 744+ foreach ( explode( ',', $scExpiryOptions ) as $option ) {
 745+ if ( strpos( $option, ":" ) === false ) {
 746+ $show = $value = $option;
 747+ } else {
 748+ list( $show, $value ) = explode( ":", $option );
 749+ }
 750+ $show = htmlspecialchars( $show );
 751+ $value = htmlspecialchars( $value );
 752+ $expiryFormOptions .= Xml::option( $show, $value, $expirySelect == $value ) . "\n";
 753+ }
 754+ # Actually add expiry dropdown to form
 755+ $output .= "<table>"; // expiry table start
 756+ if ( $showProtectOptions && $isAllowed ) {
 757+ $output .= "
 758+ <tr>
 759+ <td class='mw-label'>" .
 760+ Xml::label( wfMsg( 'stabilization-expiry' ),
 761+ 'mwStabilizeExpirySelection' ) .
 762+ "</td>
 763+ <td class='mw-input'>" .
 764+ Xml::tags( 'select',
 765+ array(
 766+ 'id' => 'mwStabilizeExpirySelection',
 767+ 'name' => 'mwStabilizeExpirySelection',
 768+ 'onchange' => 'onFRChangeExpiryDropdown()',
 769+ ) + $disabledAttrib,
 770+ $expiryFormOptions ) .
 771+ "</td>
 772+ </tr>";
 773+ }
 774+ # Add custom expiry field to form
 775+ $attribs = array( 'id' => 'mwStabilizeExpiryOther',
 776+ 'onkeyup' => 'onFRChangeExpiryField()' ) + $disabledAttrib;
 777+ $output .= "
 778+ <tr>
 779+ <td class='mw-label'>" .
 780+ Xml::label( wfMsg( 'stabilization-othertime' ), 'mwStabilizeExpiryOther' ) .
 781+ '</td>
 782+ <td class="mw-input">' .
 783+ Xml::input( 'mwStabilizeExpiryOther', 50, $expiryOther, $attribs ) .
 784+ '</td>
 785+ </tr>';
 786+ $output .= "</table>"; // expiry table end
 787+ # Close field set and table row
 788+ $output .= Xml::closeElement( 'fieldset' );
 789+ $output .= "</td></tr>";
 790+
 791+ # Add some javascript for expiry dropdowns
 792+ $wgOut->addScript(
 793+ "<script type=\"text/javascript\">
 794+ function onFRChangeExpiryDropdown() {
 795+ document.getElementById('mwStabilizeExpiryOther').value = '';
 796+ }
 797+ function onFRChangeExpiryField() {
 798+ document.getElementById('mwStabilizeExpirySelection').value = 'othertime';
 799+ }
 800+ </script>"
 801+ );
 802+ return true;
 803+ }
 804+
 805+ // Add stability log extract to protection form
 806+ public static function insertStabilityLog( Article $article, OutputPage $out ) {
 807+ if ( !$article->exists() ) {
 808+ return true; // nothing to do
 809+ } else if ( !FlaggedRevs::inReviewNamespace( $article->getTitle() ) ) {
 810+ return true; // not a reviewable page
 811+ }
 812+ # Show relevant lines from the stability log:
 813+ $out->addHTML( Xml::element( 'h2', null, LogPage::logName( 'stable' ) ) );
 814+ LogEventsList::showLogExtract( $out, 'stable', $article->getTitle()->getPrefixedText() );
 815+ return true;
 816+ }
 817+
 818+ // Update stability config from request
 819+ public static function onProtectionSave( Article $article, &$errorMsg ) {
 820+ global $wgUser, $wgRequest;
 821+ if ( !$article->exists() ) {
 822+ return true; // simple custom levels set for action=protect
 823+ } elseif ( !FlaggedRevs::inReviewNamespace( $article->getTitle() ) ) {
 824+ return true; // not a reviewable page
 825+ } elseif ( wfReadOnly() || !$wgUser->isAllowed( 'stablesettings' ) ) {
 826+ return true; // user cannot change anything
 827+ }
 828+ $form = new PageStabilityProtectForm( $wgUser );
 829+ $form->setPage( $article->getTitle() ); // target page
 830+ $permission = $wgRequest->getVal( 'mwStabilityLevel' );
 831+ if ( $permission == "none" ) {
 832+ $permission = ''; // 'none' => ''
 833+ }
 834+ $form->setAutoreview( $permission ); // protection level (autoreview restriction)
 835+ $form->setWatchThis( null ); // protection form already has a watch check
 836+ $form->setReasonExtra( $wgRequest->getText( 'mwProtect-reason' ) ); // manual
 837+ $form->setReasonSelection( $wgRequest->getVal( 'wpProtectReasonSelection' ) ); // dropdown
 838+ $form->setExpiryCustom( $wgRequest->getVal( 'mwStabilizeExpiryOther' ) ); // manual
 839+ $form->setExpirySelection( $wgRequest->getVal( 'mwStabilizeExpirySelection' ) ); // dropdown
 840+ $form->ready(); // params all set
 841+ if ( $wgRequest->wasPosted() && $form->isAllowed() ) {
 842+ $status = $form->submit();
 843+ if ( $status !== true ) {
 844+ $errorMsg = wfMsg( $status ); // some error message
 845+ }
 846+ }
 847+ return true;
 848+ }
 849+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/FlaggedRevsUI.hooks.php
___________________________________________________________________
Added: svn:eol-style
1850 + native
Index: trunk/extensions/FlaggedRevs/presentation/specialpages/actions/RevisionReview_body.php
@@ -84,7 +84,7 @@
8585 }
8686 // Use confirmation screen for reject...
8787 if ( $form->getAction() == 'reject' && !$wgRequest->getBool( 'wpRejectConfirm' ) ) {
88 - $rejectForm = new RejectConfirmationFormGUI( $form );
 88+ $rejectForm = new RejectConfirmationFormUI( $form );
8989 list( $html, $status ) = $rejectForm->getHtml();
9090 // Success...
9191 if ( $status === true ) {
Index: trunk/extensions/FlaggedRevs/presentation/FlaggedPageView.php
@@ -1070,7 +1070,7 @@
10711071 }
10721072 # Build the review form as needed
10731073 if ( $rev && ( !$this->diffRevs || $this->isReviewableDiff ) ) {
1074 - $form = new RevisionReviewFormGUI( $wgUser, $this->article, $rev );
 1074+ $form = new RevisionReviewFormUI( $wgUser, $this->article, $rev );
10751075 # Default tags and existence of "reject" button depend on context
10761076 if ( $this->diffRevs ) {
10771077 $form->setDiffPriorRev( $this->diffRevs['old'] );
Index: trunk/extensions/FlaggedRevs/presentation/RevisionReviewFormUI.php
@@ -0,0 +1,392 @@
 2+<?php
 3+/**
 4+ * Main review form UI
 5+ *
 6+ * NOTE: use ONLY for diff-to-stable views and page version views
 7+ */
 8+class RevisionReviewFormUI {
 9+ protected $user, $article, $rev;
 10+ protected $refRev = null;
 11+ protected $topNotice = '';
 12+ protected $templateIDs = null, $imageSHA1Keys = null;
 13+
 14+ /**
 15+ * Generates a brief review form for a page
 16+ * @param User $user
 17+ * @param FlaggedPage $article
 18+ * @param Revision $rev
 19+ */
 20+ public function __construct( User $user, FlaggedPage $article, Revision $rev ) {
 21+ $this->user = $user;
 22+ $this->article = $article;
 23+ $this->rev = $rev;
 24+ }
 25+
 26+ /*
 27+ * Call this only when the form is shown on a diff:
 28+ * (a) Shows the "reject" button
 29+ * (b) Default the rating tags to those of $this->rev (if flagged)
 30+ * @param Revision $refRev Old revision for diffs ($this->rev is the new rev)
 31+ */
 32+ public function setDiffPriorRev( Revision $refRev ) {
 33+ $this->refRev = $refRev;
 34+ }
 35+
 36+ /*
 37+ * Add on a notice inside the review box at the top
 38+ * @param string $topNotice Text to
 39+ */
 40+ public function setTopNotice( $topNotice ) {
 41+ $this->topNotice = (string)$topNotice;
 42+ }
 43+
 44+ /*
 45+ * Set the template/file version parameters corresponding to what the user is viewing
 46+ * @param string $topNotice Text to
 47+ */
 48+ public function setIncludeVersions( array $templateIDs, array $imageSHA1Keys ) {
 49+ $this->templateIDs = $templateIDs;
 50+ $this->imageSHA1Keys = $imageSHA1Keys;
 51+ }
 52+
 53+ /**
 54+ * Generates a brief review form for a page
 55+ * @return array (html string, error string or true)
 56+ */
 57+ public function getHtml() {
 58+ global $wgOut, $wgLang, $wgParser, $wgEnableParserCache;
 59+ $revId = $this->rev->getId();
 60+ if ( $this->rev->isDeleted( Revision::DELETED_TEXT ) ) {
 61+ return array( '', 'review_bad_oldid' ); # The revision must be valid and public
 62+ }
 63+ $article = $this->article; // convenience
 64+
 65+ $srev = $article->getStableRev();
 66+ # See if the version being displayed is flagged...
 67+ if ( $revId == $article->getStable() ) {
 68+ $frev = $srev; // avoid query
 69+ } else {
 70+ $frev = FlaggedRevision::newFromTitle( $article->getTitle(), $revId );
 71+ }
 72+ $oldFlags = $frev
 73+ ? $frev->getTags() // existing tags
 74+ : FlaggedRevs::quickTags( FR_CHECKED ); // basic tags
 75+ $reviewTime = $frev ? $frev->getTimestamp() : ''; // last review of rev
 76+
 77+ $priorRevId = $this->refRev ? $this->refRev->getId() : 0;
 78+ # If we are reviewing updates to a page, start off with the stable revision's
 79+ # flags. Otherwise, we just fill them in with the selected revision's flags.
 80+ # @TODO: do we want to carry over info for other diffs?
 81+ if ( $srev && $srev->getRevId() == $priorRevId ) { // diff-to-stable
 82+ $flags = $srev->getTags();
 83+ # Check if user is allowed to renew the stable version.
 84+ # If not, then get the flags for the new revision itself.
 85+ if ( !FlaggedRevs::userCanSetFlags( $this->user, $oldFlags ) ) {
 86+ $flags = $oldFlags;
 87+ }
 88+ # Re-review button is need for template/file only review case
 89+ $reviewIncludes = ( $srev->getRevId() == $revId && !$article->stableVersionIsSynced() );
 90+ } else { // views
 91+ $flags = $oldFlags;
 92+ $reviewIncludes = false; // re-review button not needed
 93+ }
 94+
 95+ # Disable form for unprivileged users
 96+ $disabled = array();
 97+ if ( !$article->getTitle()->quickUserCan( 'review' ) ||
 98+ !$article->getTitle()->quickUserCan( 'edit' ) ||
 99+ !FlaggedRevs::userCanSetFlags( $this->user, $flags ) )
 100+ {
 101+ $disabled = array( 'disabled' => 'disabled' );
 102+ }
 103+
 104+ # Begin form...
 105+ $reviewTitle = SpecialPage::getTitleFor( 'RevisionReview' );
 106+ $action = $reviewTitle->getLocalUrl( 'action=submit' );
 107+ $params = array( 'method' => 'post', 'action' => $action, 'id' => 'mw-fr-reviewform' );
 108+ $form = Xml::openElement( 'form', $params );
 109+ $form .= Xml::openElement( 'fieldset',
 110+ array( 'class' => 'flaggedrevs_reviewform noprint' ) );
 111+ # Add appropriate legend text
 112+ $legendMsg = $frev ? 'revreview-reflag' : 'revreview-flag';
 113+ $form .= Xml::openElement( 'legend', array( 'id' => 'mw-fr-reviewformlegend' ) );
 114+ $form .= "<strong>" . wfMsgHtml( $legendMsg ) . "</strong>";
 115+ $form .= Xml::closeElement( 'legend' ) . "\n";
 116+ # Show explanatory text
 117+ $form .= $this->topNotice;
 118+ # Show possible conflict warning msg...
 119+ if ( $priorRevId ) {
 120+ list( $u, $ts ) =
 121+ FRUserActivity::getUserReviewingDiff( $priorRevId, $this->rev->getId() );
 122+ } else {
 123+ list( $u, $ts ) = FRUserActivity::getUserReviewingPage( $this->rev->getPage() );
 124+ }
 125+ if ( $u !== null && $u != $this->user->getName() ) {
 126+ $msg = $priorRevId ? 'revreview-poss-conflict-c' : 'revreview-poss-conflict-p';
 127+ $form .= '<p><span class="fr-under-review">' .
 128+ wfMsgExt( $msg, 'parseinline',
 129+ $u, $wgLang->date( $ts, true ), $wgLang->time( $ts, true ) ) .
 130+ '</span></p>';
 131+ }
 132+
 133+ if ( $disabled ) {
 134+ $form .= Xml::openElement( 'div', array( 'class' => 'fr-rating-controls-disabled',
 135+ 'id' => 'fr-rating-controls-disabled' ) );
 136+ } else {
 137+ $form .= Xml::openElement( 'div', array( 'class' => 'fr-rating-controls',
 138+ 'id' => 'fr-rating-controls' ) );
 139+ }
 140+
 141+ # Add main checkboxes/selects
 142+ $form .= Xml::openElement( 'span',
 143+ array( 'id' => 'mw-fr-ratingselects', 'class' => 'fr-rating-options' ) );
 144+ $form .= self::ratingInputs( $this->user, $flags, (bool)$disabled, (bool)$frev );
 145+ $form .= Xml::closeElement( 'span' );
 146+
 147+ # Get template/file version info as needed
 148+ list( $templateIDs, $imageSHA1Keys ) = $this->getIncludeVersions();
 149+ # Convert these into flat string params
 150+ list( $templateParams, $imageParams, $fileVersion ) =
 151+ RevisionReviewForm::getIncludeParams( $article, $templateIDs, $imageSHA1Keys );
 152+
 153+ $form .= Xml::openElement( 'span', array( 'style' => 'white-space: nowrap;' ) );
 154+ # Hide comment input if needed
 155+ if ( !$disabled ) {
 156+ if ( count( FlaggedRevs::getTags() ) > 1 ) {
 157+ $form .= "<br />"; // Don't put too much on one line
 158+ }
 159+ $form .= "<span id='mw-fr-commentbox' style='clear:both'>" .
 160+ Xml::inputLabel( wfMsg( 'revreview-log' ), 'wpReason', 'wpReason', 40, '',
 161+ array( 'class' => 'fr-comment-box' ) ) . "&#160;&#160;&#160;</span>";
 162+ }
 163+ # Determine if there will be reject button
 164+ $rejectId = $this->rejectRefRevId();
 165+ # Add the submit buttons
 166+ $form .= self::submitButtons( $rejectId, $frev, (bool)$disabled, $reviewIncludes );
 167+ # Show stability log if there is anything interesting...
 168+ if ( $article->isPageLocked() ) {
 169+ $form .= ' ' . FlaggedRevsXML::logToggle( 'revreview-log-toggle-show' );
 170+ }
 171+ $form .= Xml::closeElement( 'span' );
 172+ # ..add the actual stability log body here
 173+ if ( $article->isPageLocked() ) {
 174+ $form .= FlaggedRevsXML::stabilityLogExcerpt( $article );
 175+ }
 176+ $form .= Xml::closeElement( 'div' ) . "\n";
 177+
 178+ # Hidden params
 179+ $form .= Html::hidden( 'title', $reviewTitle->getPrefixedText() ) . "\n";
 180+ $form .= Html::hidden( 'target', $article->getTitle()->getPrefixedDBKey() ) . "\n";
 181+ $form .= Html::hidden( 'refid', $priorRevId ) . "\n";
 182+ $form .= Html::hidden( 'oldid', $revId ) . "\n";
 183+ $form .= Html::hidden( 'action', 'submit' ) . "\n";
 184+ $form .= Html::hidden( 'wpEditToken', $this->user->editToken() ) . "\n";
 185+ $form .= Html::hidden( 'changetime', $reviewTime,
 186+ array( 'id' => 'mw-fr-input-changetime' ) ); // id for JS
 187+ # Add review parameters
 188+ $form .= Html::hidden( 'templateParams', $templateParams ) . "\n";
 189+ $form .= Html::hidden( 'imageParams', $imageParams ) . "\n";
 190+ $form .= Html::hidden( 'fileVersion', $fileVersion ) . "\n";
 191+ # Special token to discourage fiddling...
 192+ $checkCode = RevisionReviewForm::validationKey(
 193+ $templateParams, $imageParams, $fileVersion, $revId
 194+ );
 195+ $form .= Html::hidden( 'validatedParams', $checkCode ) . "\n";
 196+
 197+ $form .= Xml::closeElement( 'fieldset' );
 198+ $form .= Xml::closeElement( 'form' );
 199+
 200+ return array( $form, true /* ok */ );
 201+ }
 202+
 203+ /*
 204+ * If the REJECT button should show then get the ID of the last good rev
 205+ * @return int
 206+ */
 207+ protected function rejectRefRevId() {
 208+ if ( $this->refRev ) {
 209+ $priorId = $this->refRev->getId();
 210+ if ( $priorId == $this->article->getStable() && $priorId != $this->rev->getId() ) {
 211+ if ( $this->rev->getRawText() != $this->refRev->getRawText() ) {
 212+ return $priorId; // left rev must be stable and right one newer
 213+ }
 214+ }
 215+ }
 216+ return 0;
 217+ }
 218+
 219+ /**
 220+ * @param User $user
 221+ * @param array $flags, selected flags
 222+ * @param bool $disabled, form disabled
 223+ * @param bool $reviewed, rev already reviewed
 224+ * @return string
 225+ * Generates a main tag inputs (checkboxes/radios/selects) for review form
 226+ */
 227+ protected static function ratingInputs( $user, $flags, $disabled, $reviewed ) {
 228+ # Get all available tags for this page/user
 229+ list( $labels, $minLevels ) = self::ratingFormTags( $user, $flags );
 230+ if ( $labels === false ) {
 231+ $disabled = true; // a tag is unsettable
 232+ }
 233+ # If there are no tags, make one checkbox to approve/unapprove
 234+ if ( FlaggedRevs::binaryFlagging() ) {
 235+ return '';
 236+ }
 237+ $items = array();
 238+ # Build rating form...
 239+ if ( $disabled ) {
 240+ // Display the value for each tag as text
 241+ foreach ( FlaggedRevs::getTags() as $quality ) {
 242+ $selected = isset( $flags[$quality] ) ? $flags[$quality] : 0;
 243+ $items[] = FlaggedRevs::getTagMsg( $quality ) . ": " .
 244+ FlaggedRevs::getTagValueMsg( $quality, $selected );
 245+ }
 246+ } else {
 247+ $size = count( $labels, 1 ) - count( $labels );
 248+ foreach ( $labels as $quality => $levels ) {
 249+ $item = '';
 250+ $numLevels = count( $levels );
 251+ $minLevel = $minLevels[$quality];
 252+ # Determine the level selected by default
 253+ if ( !empty( $flags[$quality] ) && isset( $levels[$flags[$quality]] ) ) {
 254+ $selected = $flags[$quality]; // valid non-zero value
 255+ } else {
 256+ $selected = $minLevel;
 257+ }
 258+ # Show label as needed
 259+ if ( !FlaggedRevs::binaryFlagging() ) {
 260+ $item .= Xml::tags( 'label', array( 'for' => "wp$quality" ),
 261+ FlaggedRevs::getTagMsg( $quality ) ) . ":\n";
 262+ }
 263+ # If the sum of qualities of all flags is above 6, use drop down boxes.
 264+ # 6 is an arbitrary value choosen according to screen space and usability.
 265+ if ( $size > 6 ) {
 266+ $attribs = array( 'name' => "wp$quality", 'id' => "wp$quality",
 267+ 'onchange' => "FlaggedRevsReview.updateRatingForm()" );
 268+ $item .= Xml::openElement( 'select', $attribs ) . "\n";
 269+ foreach ( $levels as $i => $name ) {
 270+ $optionClass = array( 'class' => "fr-rating-option-$i" );
 271+ $item .= Xml::option( FlaggedRevs::getTagMsg( $name ), $i,
 272+ ( $i == $selected ), $optionClass ) . "\n";
 273+ }
 274+ $item .= Xml::closeElement( 'select' ) . "\n";
 275+ # If there are more than two levels, current user gets radio buttons
 276+ } elseif ( $numLevels > 2 ) {
 277+ foreach ( $levels as $i => $name ) {
 278+ $attribs = array( 'class' => "fr-rating-option-$i",
 279+ 'onchange' => "FlaggedRevsReview.updateRatingForm()" );
 280+ $item .= Xml::radioLabel( FlaggedRevs::getTagMsg( $name ), "wp$quality",
 281+ $i, "wp$quality" . $i, ( $i == $selected ), $attribs ) . "\n";
 282+ }
 283+ # Otherwise make checkboxes (two levels available for current user)
 284+ } else if ( $numLevels == 2 ) {
 285+ $i = $minLevel;
 286+ $attribs = array( 'class' => "fr-rating-option-$i",
 287+ 'onchange' => "FlaggedRevsReview.updateRatingForm()" );
 288+ $attribs = $attribs + array( 'value' => $i );
 289+ $item .= Xml::checkLabel( wfMsg( 'revreview-' . $levels[$i] ),
 290+ "wp$quality", "wp$quality", ( $selected == $i ), $attribs ) . "\n";
 291+ }
 292+ $items[] = $item;
 293+ }
 294+ }
 295+ return implode( '&#160;&#160;&#160;', $items );
 296+ }
 297+
 298+ protected static function ratingFormTags( $user, $selected ) {
 299+ $labels = array();
 300+ $minLevels = array();
 301+ # Build up all levels available to user
 302+ foreach ( FlaggedRevs::getDimensions() as $tag => $levels ) {
 303+ if ( isset( $selected[$tag] ) &&
 304+ !FlaggedRevs::userCanSetTag( $user, $tag, $selected[$tag] ) )
 305+ {
 306+ return array( false, false ); // form will have to be disabled
 307+ }
 308+ $labels[$tag] = array(); // applicable tag levels
 309+ $minLevels[$tag] = false; // first non-zero level number
 310+ foreach ( $levels as $i => $msg ) {
 311+ # Some levels may be restricted or not applicable...
 312+ if ( !FlaggedRevs::userCanSetTag( $user, $tag, $i ) ) {
 313+ continue; // skip this level
 314+ } else if ( $i > 0 && !$minLevels[$tag] ) {
 315+ $minLevels[$tag] = $i; // first non-zero level number
 316+ }
 317+ $labels[$tag][$i] = $msg; // set label
 318+ }
 319+ if ( !$minLevels[$tag] ) {
 320+ return array( false, false ); // form will have to be disabled
 321+ }
 322+ }
 323+ return array( $labels, $minLevels );
 324+ }
 325+
 326+ /**
 327+ * Generates review form submit buttons
 328+ * @param int $rejectId left rev ID for "reject" on diffs
 329+ * @param FlaggedRevision $frev, the flagged revision, if any
 330+ * @param bool $disabled, is the form disabled?
 331+ * @param bool $reviewIncludes, force the review button to be usable?
 332+ * @return string
 333+ */
 334+ protected static function submitButtons(
 335+ $rejectId, $frev, $disabled, $reviewIncludes = false
 336+ ) {
 337+ $disAttrib = array( 'disabled' => 'disabled' );
 338+ # ACCEPT BUTTON: accept a revision
 339+ # We may want to re-review to change:
 340+ # (a) notes (b) tags (c) pending template/file changes
 341+ if ( FlaggedRevs::binaryFlagging() ) { // just the buttons
 342+ $applicable = ( !$frev || $reviewIncludes ); // no tags/notes
 343+ $needsChange = false; // no state change possible
 344+ } else { // buttons + ratings
 345+ $applicable = true; // tags might change
 346+ $needsChange = ( $frev && !$reviewIncludes );
 347+ }
 348+ $s = Xml::submitButton( wfMsgHtml( 'revreview-submit-review' ),
 349+ array(
 350+ 'name' => 'wpApprove',
 351+ 'id' => 'mw-fr-submit-accept',
 352+ 'accesskey' => wfMsg( 'revreview-ak-review' ),
 353+ 'title' => wfMsg( 'revreview-tt-flag' ) . ' [' .
 354+ wfMsg( 'revreview-ak-review' ) . ']'
 355+ ) + ( ( $disabled || !$applicable ) ? $disAttrib : array() )
 356+ );
 357+ # REJECT BUTTON: revert from a pending revision to the stable
 358+ if ( $rejectId ) {
 359+ $s .= ' ';
 360+ $s .= Xml::submitButton( wfMsgHtml( 'revreview-submit-reject' ),
 361+ array(
 362+ 'name' => 'wpReject',
 363+ 'id' => 'mw-fr-submit-reject',
 364+ 'title' => wfMsg( 'revreview-tt-reject' ),
 365+ ) + ( $disabled ? $disAttrib : array() )
 366+ );
 367+ }
 368+ # UNACCEPT BUTTON: revoke a revisions acceptance
 369+ # Hide if revision is not flagged
 370+ $s .= ' ';
 371+ $s .= Xml::submitButton( wfMsgHtml( 'revreview-submit-unreview' ),
 372+ array(
 373+ 'name' => 'wpUnapprove',
 374+ 'id' => 'mw-fr-submit-unaccept',
 375+ 'title' => wfMsg( 'revreview-tt-unflag' ),
 376+ 'style' => $frev ? '' : 'display:none'
 377+ ) + ( $disabled ? $disAttrib : array() )
 378+ );
 379+ // Disable buttons unless state changes in some cases (non-JS compatible)
 380+ $s .= "<script type=\"text/javascript\">
 381+ var jsReviewNeedsChange = " . (int)$needsChange . "</script>";
 382+ return $s;
 383+ }
 384+
 385+ protected function getIncludeVersions() {
 386+ # Do we need to get inclusion IDs from parser output?
 387+ if ( $this->templateIDs === null || $this->imageSHA1Keys === null ) {
 388+ list( $this->templateIDs, $this->imageSHA1Keys ) =
 389+ RevisionReviewForm::currentIncludeVersions( $this->article, $this->rev );
 390+ }
 391+ return array( $this->templateIDs, $this->imageSHA1Keys );
 392+ }
 393+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/RevisionReviewFormUI.php
___________________________________________________________________
Added: svn:eol-style
1394 + native
Index: trunk/extensions/FlaggedRevs/presentation/RejectConfirmationFormUI.php
@@ -0,0 +1,145 @@
 2+<?php
 3+/**
 4+ * Reject confirmation review form UI
 5+ */
 6+class RejectConfirmationFormUI {
 7+ protected $form, $oldRev, $newRev;
 8+
 9+ public function __construct( RevisionReviewForm $form ) {
 10+ $this->form = $form;
 11+ $this->newRev = Revision::newFromTitle( $form->getPage(), $form->getOldId() );
 12+ $this->oldRev = Revision::newFromTitle( $form->getPage(), $form->getRefId() );
 13+ }
 14+
 15+ /**
 16+ * Get the "are you sure you want to reject these changes?" form
 17+ * @return array (html string, error string or true)
 18+ */
 19+ public function getHtml() {
 20+ global $wgLang, $wgContLang;
 21+ $status = $this->form->checkTarget();
 22+ if ( $status !== true ) {
 23+ return array( '', $status ); // not a reviewable existing page
 24+ }
 25+ $oldRev = $this->oldRev; // convenience
 26+ $newRev = $this->newRev; // convenience
 27+ # Do not mess with archived/deleted revisions
 28+ if ( !$oldRev || $newRev->isDeleted( Revision::DELETED_TEXT ) ) {
 29+ return array( '', 'review_bad_oldid' );
 30+ } elseif ( !$newRev || $newRev->isDeleted( Revision::DELETED_TEXT ) ) {
 31+ return array( '', 'review_bad_oldid' );
 32+ }
 33+
 34+ $form = '<div class="plainlinks">';
 35+
 36+ $dbr = wfGetDB( DB_SLAVE );
 37+ $res = $dbr->select( 'revision',
 38+ Revision::selectFields(),
 39+ array(
 40+ 'rev_page' => $oldRev->getPage(),
 41+ 'rev_id > ' . $dbr->addQuotes( $oldRev->getId() ),
 42+ 'rev_id <= ' . $dbr->addQuotes( $newRev->getId() )
 43+ ),
 44+ __METHOD__,
 45+ array( 'LIMIT' => 251 ) // sanity check
 46+ );
 47+ if ( !$dbr->numRows( $res ) ) {
 48+ return array( '', 'review_bad_oldid' );
 49+ } elseif ( $dbr->numRows( $res ) > 250 ) {
 50+ return array( '', 'review_reject_excessive' );
 51+ }
 52+
 53+ $rejectIds = $rejectAuthors = array();
 54+ $contribs = SpecialPage::getTitleFor( 'Contributions' )->getPrefixedText();
 55+ foreach ( $res as $row ) {
 56+ $rev = new Revision( $row );
 57+ $rejectIds[] = $rev->getId();
 58+ $rejectAuthors[] = $rev->isDeleted( Revision::DELETED_USER )
 59+ ? wfMsg( 'rev-deleted-user' )
 60+ : "[[{$contribs}/{$rev->getUserText()}|{$rev->getUserText()}]]";
 61+ }
 62+ $rejectAuthors = array_values( array_unique( $rejectAuthors ) );
 63+
 64+ // List of revisions being undone...
 65+ $form .= wfMsgExt( 'revreview-reject-text-list', 'parseinline',
 66+ $wgLang->formatNum( count( $rejectIds ) ) );
 67+ $form .= '<ul>';
 68+ // FIXME: we need a generic revision list class...this is bullshit
 69+ $spRevDelete = SpecialPage::getPage( 'RevisionReview' );
 70+ $spRevDelete->skin = $this->form->getUser()->getSkin(); // XXX
 71+ $list = new RevDel_RevisionList( $spRevDelete, $oldRev->getTitle(), $rejectIds );
 72+ for ( $list->reset(); $list->current(); $list->next() ) {
 73+ $item = $list->current();
 74+ if ( $item->canView() ) {
 75+ $form .= $item->getHTML();
 76+ }
 77+ }
 78+ $form .= '</ul>';
 79+ if ( $newRev->isCurrent() ) {
 80+ // Revision this will revert to (when reverting the top X revs)...
 81+ $form .= wfMsgExt( 'revreview-reject-text-revto', 'parseinline',
 82+ $oldRev->getTitle()->getPrefixedDBKey(), $oldRev->getId(),
 83+ $wgLang->timeanddate( $oldRev->getTimestamp(), true )
 84+ );
 85+ }
 86+
 87+ $comment = $this->form->getComment(); // convenience
 88+ // Determine the default edit summary...
 89+ $oldRevAuthor = $oldRev->isDeleted( Revision::DELETED_USER )
 90+ ? wfMsg( 'rev-deleted-user' )
 91+ : $oldRev->getUserText();
 92+ // NOTE: *-cur msg wording not safe for (unlikely) edit auto-merge
 93+ $msg = $newRev->isCurrent()
 94+ ? 'revreview-reject-summary-cur'
 95+ : 'revreview-reject-summary-old';
 96+ $defaultSummary = wfMsgExt( $msg, array( 'parsemag', 'content' ),
 97+ $wgContLang->formatNum( count( $rejectIds ) ),
 98+ $wgContLang->listToText( $rejectAuthors ),
 99+ $oldRev->getId(),
 100+ $oldRevAuthor );
 101+ // If the message is too big, then fallback to the shorter one
 102+ $colonSeparator = wfMsgForContent( 'colon-separator' );
 103+ $maxLen = 255 - count( $colonSeparator ) - count( $comment );
 104+ if ( strlen( $defaultSummary ) > $maxLen ) {
 105+ $msg = $newRev->isCurrent()
 106+ ? 'revreview-reject-summary-cur-short'
 107+ : 'revreview-reject-summary-old-short';
 108+ $defaultSummary = wfMsgExt( $msg, array( 'parsemag', 'content' ),
 109+ $wgContLang->formatNum( count( $rejectIds ) ),
 110+ $oldRev->getId(),
 111+ $oldRevAuthor );
 112+ }
 113+ // Append any review comment...
 114+ if ( $comment != '' ) {
 115+ if ( $defaultSummary != '' ) {
 116+ $defaultSummary .= $colonSeparator;
 117+ }
 118+ $defaultSummary .= $comment;
 119+ }
 120+
 121+ $form .= '</div>';
 122+
 123+ $skin = $this->form->getUser()->getSkin();
 124+ $reviewTitle = SpecialPage::getTitleFor( 'RevisionReview' );
 125+ $form .= Xml::openElement( 'form',
 126+ array( 'method' => 'POST', 'action' => $reviewTitle->getFullUrl() ) );
 127+ $form .= Html::hidden( 'action', 'reject' );
 128+ $form .= Html::hidden( 'wpReject', 1 );
 129+ $form .= Html::hidden( 'wpRejectConfirm', 1 );
 130+ $form .= Html::hidden( 'oldid', $this->form->getOldId() );
 131+ $form .= Html::hidden( 'refid', $this->form->getRefId() );
 132+ $form .= Html::hidden( 'target', $oldRev->getTitle()->getPrefixedDBKey() );
 133+ $form .= Html::hidden( 'wpEditToken', $this->form->getUser()->editToken() );
 134+ $form .= Html::hidden( 'changetime', $newRev->getTimestamp() );
 135+ $form .= Xml::inputLabel( wfMsg( 'revreview-reject-summary' ), 'wpReason',
 136+ 'wpReason', 120, $defaultSummary ) . "<br />";
 137+ $form .= Html::input( 'wpSubmit', wfMsg( 'revreview-reject-confirm' ), 'submit' );
 138+ $form .= ' ';
 139+ $form .= $skin->link( $this->form->getPage(), wfMsg( 'revreview-reject-cancel' ),
 140+ array( 'onClick' => 'history.back(); return false;' ),
 141+ array( 'oldid' => $this->form->getRefId(), 'diff' => $this->form->getOldId() ) );
 142+ $form .= Xml::closeElement( 'form' );
 143+
 144+ return array( $form, true );
 145+ }
 146+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/RejectConfirmationFormUI.php
___________________________________________________________________
Added: svn:eol-style
1147 + native

Status & tagging log