r85750 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r85749‎ | r85750 | r85751 >
Date:07:58, 10 April 2011
Author:aaron
Status:resolved
Tags:
Comment:
Moved /specialpages and /modules under /presentation
Modified paths:
  • /trunk/extensions/FlaggedRevs/FlaggedRevs.php (modified) (history)
  • /trunk/extensions/FlaggedRevs/modules (deleted) (history)
  • /trunk/extensions/FlaggedRevs/presentation/modules (added) (history)
  • /trunk/extensions/FlaggedRevs/presentation/specialpages (added) (history)
  • /trunk/extensions/FlaggedRevs/specialpages (deleted) (history)

Diff [purge]

Index: trunk/extensions/FlaggedRevs/FlaggedRevs.php
@@ -274,7 +274,7 @@
275275 $wgExtensionMessagesFiles['FlaggedRevs'] = $langDir . 'FlaggedRevs.i18n.php';
276276 $wgExtensionAliasesFiles['FlaggedRevs'] = $langDir . 'FlaggedRevs.alias.php';
277277
278 -$specialActionDir = $dir . 'specialpages/actions/';
 278+$specialActionDir = $dir . 'presentation/specialpages/actions/';
279279 # Load revision review UI
280280 $wgAutoloadClasses['RevisionReview'] = $specialActionDir . 'RevisionReview_body.php';
281281 // @TODO: move review action related messages to separate file?
@@ -282,7 +282,7 @@
283283 $wgAutoloadClasses['Stabilization'] = $specialActionDir . 'Stabilization_body.php';
284284 $wgExtensionMessagesFiles['Stabilization'] = $langDir . 'Stabilization.i18n.php';
285285
286 -$specialReportDir = $dir . 'specialpages/reports/';
 286+$specialReportDir = $dir . 'presentation/specialpages/reports/';
287287 # Reviewed versions list
288288 $wgAutoloadClasses['ReviewedVersions'] = $specialReportDir . 'ReviewedVersions_body.php';
289289 $wgExtensionMessagesFiles['ReviewedVersions'] = $langDir . 'ReviewedVersions.i18n.php';
@@ -355,8 +355,8 @@
356356 $wgDefaultUserOptions['flaggedrevsviewdiffs'] = false;
357357
358358 # JS/CSS modules and message bundles used by JS scripts
359 -$localModulePath = dirname( __FILE__ ) . '/modules/';
360 -$remoteModulePath = 'FlaggedRevs/modules';
 359+$localModulePath = dirname( __FILE__ ) . '/presentation/modules/';
 360+$remoteModulePath = 'FlaggedRevs/presentation/modules';
361361 $wgResourceModules['ext.flaggedRevs.basic'] = array(
362362 'styles' => array( 'flaggedrevs.css' ),
363363 'localBasePath' => $localModulePath,
Index: trunk/extensions/FlaggedRevs/presentation/specialpages/actions/Stabilization_body.php
@@ -0,0 +1,312 @@
 2+<?php
 3+
 4+// Assumes $wgFlaggedRevsProtection is off
 5+class Stabilization extends UnlistedSpecialPage {
 6+ protected $form = null;
 7+ protected $skin;
 8+
 9+ public function __construct() {
 10+ global $wgUser;
 11+ parent::__construct( 'Stabilization', 'stablesettings' );
 12+ $this->skin = $wgUser->getSkin();
 13+ }
 14+
 15+ public function execute( $par ) {
 16+ global $wgRequest, $wgUser, $wgOut;
 17+ # Check user token
 18+ $confirmed = false;
 19+ # Let anyone view, but not submit...
 20+ if ( $wgRequest->wasPosted() ) {
 21+ # Check user token
 22+ $confirmed = $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) );
 23+ if ( $wgUser->isBlocked( !$confirmed ) ) {
 24+ $wgOut->blockedPage();
 25+ return;
 26+ } elseif ( !$wgUser->isAllowed( 'stablesettings' ) ) {
 27+ $wgOut->permissionRequired( 'stablesettings' );
 28+ return;
 29+ } elseif ( wfReadOnly() ) {
 30+ $wgOut->readOnlyPage();
 31+ return;
 32+ }
 33+ }
 34+ # Set page title
 35+ $this->setHeaders();
 36+
 37+ $this->form = new PageStabilityGeneralForm( $wgUser );
 38+ $form = $this->form; // convenience
 39+ # Target page
 40+ $title = Title::newFromURL( $wgRequest->getVal( 'page', $par ) );
 41+ if ( !$title ) {
 42+ $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
 43+ return;
 44+ }
 45+ $form->setPage( $title );
 46+ # Watch checkbox
 47+ $form->setWatchThis( (bool)$wgRequest->getCheck( 'wpWatchthis' ) );
 48+ # Get auto-review option...
 49+ $form->setReviewThis( $wgRequest->getBool( 'wpReviewthis', true ) );
 50+ # Reason
 51+ $form->setReasonExtra( $wgRequest->getText( 'wpReason' ) );
 52+ $form->setReasonSelection( $wgRequest->getVal( 'wpReasonSelection' ) );
 53+ # Expiry
 54+ $form->setExpiryCustom( $wgRequest->getText( 'mwStabilize-expiry' ) );
 55+ $form->setExpirySelection( $wgRequest->getVal( 'wpExpirySelection' ) );
 56+ # Default version
 57+ $form->setOverride( (int)$wgRequest->getBool( 'wpStableconfig-override' ) );
 58+ # Get autoreview restrictions...
 59+ $form->setAutoreview( $wgRequest->getVal( 'mwProtect-level-autoreview' ) );
 60+
 61+ $status = $form->ready(); // params all set
 62+ if ( $status === 'stabilize_page_notexists' ) {
 63+ $wgOut->addWikiText(
 64+ wfMsg( 'stabilization-notexists', $title->getPrefixedText() ) );
 65+ return;
 66+ } elseif ( $status === 'stabilize_page_unreviewable' ) {
 67+ $wgOut->addWikiText(
 68+ wfMsg( 'stabilization-notcontent', $title->getPrefixedText() ) );
 69+ return;
 70+ }
 71+ # Form POST request...
 72+ if ( $confirmed && $form->isAllowed() ) {
 73+ $status = $form->submit();
 74+ if ( $status === true ) {
 75+ $wgOut->redirect( $title->getFullUrl() );
 76+ } else {
 77+ $this->showForm( wfMsg( $status ) );
 78+ }
 79+ # Form GET request...
 80+ } else {
 81+ $form->preload();
 82+ $this->showForm();
 83+ }
 84+ }
 85+
 86+ public function showForm( $err = null ) {
 87+ global $wgOut, $wgLang, $wgUser;
 88+ $form = $this->form; // convenience
 89+ $title = $this->form->getPage();
 90+ $oldConfig = $form->getOldConfig();
 91+
 92+ $s = ''; // form HTML string
 93+ # Add any error messages
 94+ if ( "" != $err ) {
 95+ $wgOut->setSubtitle( wfMsgHtml( 'formerror' ) );
 96+ $wgOut->addHTML( "<p class='error'>{$err}</p>\n" );
 97+ }
 98+ # Add header text
 99+ if ( !$form->isAllowed() ) {
 100+ $s .= wfMsgExt( 'stabilization-perm', 'parse', $title->getPrefixedText() );
 101+ } else {
 102+ $s .= wfMsgExt( 'stabilization-text', 'parse', $title->getPrefixedText() );
 103+ }
 104+ # Borrow some protection messages for dropdowns
 105+ $reasonDropDown = Xml::listDropDown(
 106+ 'wpReasonSelection',
 107+ wfMsgForContent( 'protect-dropdown' ),
 108+ wfMsgForContent( 'protect-otherreason-op' ),
 109+ $form->getReasonSelection(),
 110+ 'mwStabilize-reason',
 111+ 4
 112+ );
 113+ $scExpiryOptions = wfMsgForContent( 'protect-expiry-options' );
 114+ $showProtectOptions = ( $scExpiryOptions !== '-' && $form->isAllowed() );
 115+ $dropdownOptions = array(); // array of <label,value>
 116+ # Add the current expiry as a dropdown option
 117+ if ( $oldConfig['expiry'] && $oldConfig['expiry'] != Block::infinity() ) {
 118+ $timestamp = $wgLang->timeanddate( $oldConfig['expiry'] );
 119+ $d = $wgLang->date( $oldConfig['expiry'] );
 120+ $t = $wgLang->time( $oldConfig['expiry'] );
 121+ $dropdownOptions[] = array(
 122+ wfMsg( 'protect-existing-expiry', $timestamp, $d, $t ), 'existing' );
 123+ }
 124+ # Add "other time" expiry dropdown option
 125+ $dropdownOptions[] = array( wfMsg( 'protect-othertime-op' ), 'othertime' );
 126+ # Add custom expiry dropdown options (from MediaWiki message)
 127+ foreach( explode( ',', $scExpiryOptions ) as $option ) {
 128+ if ( strpos( $option, ":" ) === false ) {
 129+ $show = $value = $option;
 130+ } else {
 131+ list( $show, $value ) = explode( ":", $option );
 132+ }
 133+ $dropdownOptions[] = array( $show, $value );
 134+ }
 135+
 136+ # Actually build the options HTML...
 137+ $expiryFormOptions = '';
 138+ foreach ( $dropdownOptions as $option ) {
 139+ $show = htmlspecialchars( $option[0] );
 140+ $value = htmlspecialchars( $option[1] );
 141+ $expiryFormOptions .= Xml::option( $show, $value,
 142+ $form->getExpirySelection() === $value ) . "\n";
 143+ }
 144+
 145+ # Build up the form...
 146+ $s .= Xml::openElement( 'form', array( 'name' => 'stabilization',
 147+ 'action' => $this->getTitle()->getLocalUrl(), 'method' => 'post' ) );
 148+ # Add stable version override and selection options
 149+ $s .=
 150+ Xml::fieldset( wfMsg( 'stabilization-def' ), false ) . "\n" .
 151+ Xml::radioLabel( wfMsg( 'stabilization-def1' ), 'wpStableconfig-override', 1,
 152+ 'default-stable', 1 == $form->getOverride(), $this->disabledAttr() ) .
 153+ '<br />' . "\n" .
 154+ Xml::radioLabel( wfMsg( 'stabilization-def2' ), 'wpStableconfig-override', 0,
 155+ 'default-current', 0 == $form->getOverride(), $this->disabledAttr() ) . "\n" .
 156+ Xml::closeElement( 'fieldset' );
 157+ # Add autoreview restriction select
 158+ $s .= Xml::fieldset( wfMsg( 'stabilization-restrict' ), false ) .
 159+ $this->buildSelector( $form->getAutoreview() ) .
 160+ Xml::closeElement( 'fieldset' ) .
 161+
 162+ Xml::fieldset( wfMsg( 'stabilization-leg' ), false ) .
 163+ Xml::openElement( 'table' );
 164+ # Add expiry dropdown to form...
 165+ if ( $showProtectOptions && $form->isAllowed() ) {
 166+ $s .= "
 167+ <tr>
 168+ <td class='mw-label'>" .
 169+ Xml::label( wfMsg( 'stabilization-expiry' ),
 170+ 'mwStabilizeExpirySelection' ) .
 171+ "</td>
 172+ <td class='mw-input'>" .
 173+ Xml::tags( 'select',
 174+ array(
 175+ 'id' => 'mwStabilizeExpirySelection',
 176+ 'name' => 'wpExpirySelection',
 177+ 'onchange' => 'onFRChangeExpiryDropdown()',
 178+ ) + $this->disabledAttr(),
 179+ $expiryFormOptions ) .
 180+ "</td>
 181+ </tr>";
 182+ }
 183+ # Add custom expiry field to form...
 184+ $attribs = array( 'id' => "mwStabilizeExpiryOther",
 185+ 'onkeyup' => 'onFRChangeExpiryField()' ) + $this->disabledAttr();
 186+ $s .= "
 187+ <tr>
 188+ <td class='mw-label'>" .
 189+ Xml::label( wfMsg( 'stabilization-othertime' ), 'mwStabilizeExpiryOther' ) .
 190+ '</td>
 191+ <td class="mw-input">' .
 192+ Xml::input( "mwStabilize-expiry", 50, $form->getExpiryCustom(), $attribs ) .
 193+ '</td>
 194+ </tr>';
 195+ # Add comment input and submit button
 196+ if ( $form->isAllowed() ) {
 197+ $watchLabel = wfMsgExt( 'watchthis', 'parseinline' );
 198+ $watchAttribs = array( 'accesskey' => wfMsg( 'accesskey-watch' ),
 199+ 'id' => 'wpWatchthis' );
 200+ $watchChecked = ( $wgUser->getOption( 'watchdefault' )
 201+ || $title->userIsWatching() );
 202+ $reviewLabel = wfMsgExt( 'stabilization-review', 'parseinline' );
 203+
 204+ $s .= ' <tr>
 205+ <td class="mw-label">' .
 206+ xml::label( wfMsg( 'stabilization-comment' ), 'wpReasonSelection' ) .
 207+ '</td>
 208+ <td class="mw-input">' .
 209+ $reasonDropDown .
 210+ '</td>
 211+ </tr>
 212+ <tr>
 213+ <td class="mw-label">' .
 214+ Xml::label( wfMsg( 'stabilization-otherreason' ), 'wpReason' ) .
 215+ '</td>
 216+ <td class="mw-input">' .
 217+ Xml::input( 'wpReason', 70, $form->getReasonExtra(),
 218+ array( 'id' => 'wpReason' ) ) .
 219+ '</td>
 220+ </tr>
 221+ <tr>
 222+ <td></td>
 223+ <td class="mw-input">' .
 224+ Xml::check( 'wpReviewthis', $form->getReviewThis(),
 225+ array( 'id' => 'wpReviewthis' ) ) .
 226+ "<label for='wpReviewthis'>{$reviewLabel}</label>" .
 227+ '&#160;&#160;&#160;&#160;&#160;' .
 228+ Xml::check( 'wpWatchthis', $watchChecked, $watchAttribs ) .
 229+ "<label for='wpWatchthis'" . $this->skin->tooltipAndAccesskey( 'watch' ) .
 230+ ">{$watchLabel}</label>" .
 231+ '</td>
 232+ </tr>
 233+ <tr>
 234+ <td></td>
 235+ <td class="mw-submit">' .
 236+ Xml::submitButton( wfMsg( 'stabilization-submit' ) ) .
 237+ '</td>
 238+ </tr>' . Xml::closeElement( 'table' ) .
 239+ Html::hidden( 'title', $this->getTitle()->getPrefixedDBKey() ) .
 240+ Html::hidden( 'page', $title->getPrefixedText() ) .
 241+ Html::hidden( 'wpEditToken', $wgUser->editToken() );
 242+ } else {
 243+ $s .= Xml::closeElement( 'table' );
 244+ }
 245+ $s .= Xml::closeElement( 'fieldset' ) . Xml::closeElement( 'form' );
 246+
 247+ $wgOut->addHTML( $s );
 248+
 249+ $wgOut->addHTML( Xml::element( 'h2', null,
 250+ htmlspecialchars( LogPage::logName( 'stable' ) ) ) );
 251+ LogEventsList::showLogExtract( $wgOut, 'stable',
 252+ $title->getPrefixedText(), '', array( 'lim' => 25 ) );
 253+
 254+ # Add some javascript for expiry dropdowns
 255+ PageStabilityForm::addProtectionJS();
 256+ }
 257+
 258+ protected function buildSelector( $selected ) {
 259+ global $wgUser;
 260+ $allowedLevels = array();
 261+ $levels = FlaggedRevs::getRestrictionLevels();
 262+ array_unshift( $levels, '' ); // Add a "none" level
 263+ foreach ( $levels as $key ) {
 264+ # Don't let them choose levels they can't set,
 265+ # but *show* them all when the form is disabled.
 266+ if ( $this->form->isAllowed()
 267+ && !FlaggedRevs::userCanSetAutoreviewLevel( $wgUser, $key ) )
 268+ {
 269+ continue;
 270+ }
 271+ $allowedLevels[] = $key;
 272+ }
 273+ $id = 'mwProtect-level-autoreview';
 274+ $attribs = array(
 275+ 'id' => $id,
 276+ 'name' => $id,
 277+ 'size' => count( $allowedLevels ),
 278+ ) + $this->disabledAttr();
 279+
 280+ $out = Xml::openElement( 'select', $attribs );
 281+ foreach ( $allowedLevels as $key ) {
 282+ $out .= Xml::option( $this->getOptionLabel( $key ), $key, $key == $selected );
 283+ }
 284+ $out .= Xml::closeElement( 'select' );
 285+ return $out;
 286+ }
 287+
 288+ /**
 289+ * Prepare the label for a protection selector option
 290+ *
 291+ * @param string $permission Permission required
 292+ * @return string
 293+ */
 294+ protected function getOptionLabel( $permission ) {
 295+ if ( $permission == '' ) {
 296+ return wfMsg( 'stabilization-restrict-none' );
 297+ } else {
 298+ $key = "protect-level-{$permission}";
 299+ $msg = wfMsg( $key );
 300+ if ( wfEmptyMsg( $key, $msg ) ) {
 301+ $msg = wfMsg( 'protect-fallback', $permission );
 302+ }
 303+ return $msg;
 304+ }
 305+ }
 306+
 307+ // If the this form is disabled, then return the "disabled" attr array
 308+ protected function disabledAttr() {
 309+ return $this->form->isAllowed()
 310+ ? array()
 311+ : array( 'disabled' => 'disabled' );
 312+ }
 313+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/specialpages/actions/Stabilization_body.php
___________________________________________________________________
Added: svn:eol-style
1314 + native
Index: trunk/extensions/FlaggedRevs/presentation/specialpages/actions/RevisionReview_body.php
@@ -0,0 +1,305 @@
 2+<?php
 3+
 4+class RevisionReview extends UnlistedSpecialPage {
 5+ protected $form;
 6+ protected $page;
 7+ var $skin; // FIXME: with RevDel_RevisionList stuff
 8+
 9+ public function __construct() {
 10+ parent::__construct( 'RevisionReview', 'review' );
 11+ }
 12+
 13+ public function execute( $par ) {
 14+ global $wgRequest, $wgUser, $wgOut;
 15+ $confirmed = $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) );
 16+ if ( $wgUser->isAllowed( 'review' ) ) {
 17+ if ( $wgUser->isBlocked( !$confirmed ) ) {
 18+ $wgOut->blockedPage();
 19+ return;
 20+ }
 21+ } else {
 22+ $wgOut->permissionRequired( 'review' );
 23+ return;
 24+ }
 25+ if ( wfReadOnly() ) {
 26+ $wgOut->readOnlyPage();
 27+ return;
 28+ }
 29+ $this->setHeaders();
 30+
 31+ $this->skin = $wgUser->getSkin();
 32+ $this->form = new RevisionReviewForm( $wgUser );
 33+ # Our target page
 34+ $this->page = Title::newFromURL( $wgRequest->getVal( 'target' ) );
 35+ if ( !$this->page ) {
 36+ $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
 37+ return;
 38+ }
 39+
 40+ $form = $this->form; // convenience
 41+ $form->setPage( $this->page );
 42+ # Param for sites with binary flagging
 43+ $form->setApprove( $wgRequest->getCheck( 'wpApprove' ) );
 44+ $form->setUnapprove( $wgRequest->getCheck( 'wpUnapprove' ) );
 45+ $form->setReject( $wgRequest->getCheck( 'wpReject' ) );
 46+ # Rev ID
 47+ $form->setOldId( $wgRequest->getInt( 'oldid' ) );
 48+ $form->setRefId( $wgRequest->getInt( 'refid' ) );
 49+ # Special parameter mapping
 50+ $form->setTemplateParams( $wgRequest->getVal( 'templateParams' ) );
 51+ $form->setFileParams( $wgRequest->getVal( 'imageParams' ) );
 52+ $form->setFileVersion( $wgRequest->getVal( 'fileVersion' ) );
 53+ # Special token to discourage fiddling...
 54+ $form->setValidatedParams( $wgRequest->getVal( 'validatedParams' ) );
 55+ # Conflict handling
 56+ $form->setLastChangeTime( $wgRequest->getVal( 'changetime' ) );
 57+ # Tag values
 58+ foreach ( FlaggedRevs::getTags() as $tag ) {
 59+ # This can be NULL if we uncheck a checkbox
 60+ $val = $wgRequest->getInt( "wp$tag" );
 61+ $form->setDim( $tag, $val );
 62+ }
 63+ # Log comment
 64+ $form->setComment( $wgRequest->getText( 'wpReason' ) );
 65+
 66+ $status = $form->ready();
 67+ # Page must exist and be in reviewable namespace
 68+ if ( $status === 'review_page_unreviewable' ) {
 69+ $wgOut->addWikiText( wfMsg( 'revreview-main' ) );
 70+ return;
 71+ } elseif ( $status === 'review_page_notexists' ) {
 72+ $wgOut->showErrorPage( 'internalerror', 'nopagetext' );
 73+ return;
 74+ }
 75+ # Basic page permission checks...
 76+ $permErrors = $this->page->getUserPermissionsErrors( 'review', $wgUser, false );
 77+ if ( !$permErrors ) {
 78+ $permErrors = $this->page->getUserPermissionsErrors( 'edit', $wgUser, false );
 79+ }
 80+ if ( $permErrors ) {
 81+ $wgOut->showPermissionsErrorPage( $permErrors, 'review' );
 82+ return;
 83+ }
 84+
 85+ # Review the edit if requested (POST)...
 86+ if ( $wgRequest->wasPosted() ) {
 87+ // Check the edit token...
 88+ if ( !$confirmed ) {
 89+ $wgOut->addWikiText( wfMsg( 'sessionfailure' ) );
 90+ $wgOut->returnToMain( false, $this->page );
 91+ return;
 92+ }
 93+ // Use confirmation screen for reject...
 94+ if ( $form->getAction() == 'reject' && !$wgRequest->getBool( 'wpRejectConfirm' ) ) {
 95+ $rejectForm = new RejectConfirmationFormGUI( $form );
 96+ list( $html, $status ) = $rejectForm->getHtml();
 97+ // Success...
 98+ if ( $status === true ) {
 99+ $wgOut->addHtml( $html );
 100+ // Failure...
 101+ } else {
 102+ if ( $status === 'review_bad_oldid' ) {
 103+ $wgOut->showErrorPage( 'internalerror', 'revreview-revnotfound' );
 104+ } else {
 105+ $wgOut->showErrorPage( 'internalerror', $status );
 106+ }
 107+ $wgOut->returnToMain( false, $this->page );
 108+ }
 109+ // Otherwise submit...
 110+ } else {
 111+ $status = $form->submit();
 112+ // Success...
 113+ if ( $status === true ) {
 114+ $wgOut->setPageTitle( wfMsgHtml( 'actioncomplete' ) );
 115+ if ( $form->getAction() === 'approve' ) {
 116+ $wgOut->addHTML( $this->approvalSuccessHTML( true ) );
 117+ } elseif ( $form->getAction() === 'unapprove' ) {
 118+ $wgOut->addHTML( $this->deapprovalSuccessHTML( true ) );
 119+ } elseif ( $form->getAction() === 'reject' ) {
 120+ $wgOut->redirect( $this->page->getFullUrl() );
 121+ }
 122+ // Failure...
 123+ } else {
 124+ if ( $status === 'review_denied' ) {
 125+ $wgOut->permissionRequired( 'badaccess-group0' ); // protected?
 126+ } elseif ( $status === 'review_bad_key' ) {
 127+ $wgOut->permissionRequired( 'badaccess-group0' ); // fiddling
 128+ } elseif ( $status === 'review_bad_oldid' ) {
 129+ $wgOut->showErrorPage( 'internalerror', 'revreview-revnotfound' );
 130+ } elseif ( $status === 'review_not_flagged' ) {
 131+ $wgOut->redirect( $this->page->getFullUrl() ); // already unflagged
 132+ } elseif ( $status === 'review_too_low' ) {
 133+ $wgOut->addWikiText( wfMsg( 'revreview-toolow' ) );
 134+ } else {
 135+ $wgOut->showErrorPage( 'internalerror', $status );
 136+ }
 137+ $wgOut->returnToMain( false, $this->page );
 138+ }
 139+ }
 140+ // No form to view (GET)
 141+ } else {
 142+ $wgOut->returnToMain( false, $this->page );
 143+ }
 144+ }
 145+
 146+ protected function approvalSuccessHTML( $showlinks = false ) {
 147+ global $wgUser;
 148+ $title = $this->form->getPage();
 149+ # Show success message
 150+ $s = "<div class='plainlinks'>";
 151+ $s .= wfMsgExt( 'revreview-successful', 'parse',
 152+ $title->getPrefixedText(), $title->getPrefixedUrl() );
 153+ $s .= wfMsgExt( 'revreview-stable1', 'parse',
 154+ $title->getPrefixedUrl(), $this->form->getOldId() );
 155+ $s .= "</div>";
 156+ # Handy links to special pages
 157+ if ( $showlinks && $wgUser->isAllowed( 'unreviewedpages' ) ) {
 158+ $s .= $this->getSpecialLinks();
 159+ }
 160+ return $s;
 161+ }
 162+
 163+ protected function deapprovalSuccessHTML( $showlinks = false ) {
 164+ global $wgUser;
 165+ $title = $this->form->getPage();
 166+ # Show success message
 167+ $s = "<div class='plainlinks'>";
 168+ $s .= wfMsgExt( 'revreview-successful2', 'parse',
 169+ $title->getPrefixedText(), $title->getPrefixedUrl() );
 170+ $s .= wfMsgExt( 'revreview-stable2', 'parse',
 171+ $title->getPrefixedUrl(), $this->form->getOldId() );
 172+ $s .= "</div>";
 173+ # Handy links to special pages
 174+ if ( $showlinks && $wgUser->isAllowed( 'unreviewedpages' ) ) {
 175+ $s .= $this->getSpecialLinks();
 176+ }
 177+ return $s;
 178+ }
 179+
 180+ protected function getSpecialLinks() {
 181+ $s = '<p>' . wfMsgHtml( 'returnto',
 182+ $this->skin->linkKnown( SpecialPage::getTitleFor( 'UnreviewedPages' ) )
 183+ ) . '</p>';
 184+ $s .= '<p>' . wfMsgHtml( 'returnto',
 185+ $this->skin->linkKnown( SpecialPage::getTitleFor( 'PendingChanges' ) )
 186+ ) . '</p>';
 187+ return $s;
 188+ }
 189+
 190+ public static function AjaxReview( /*$args...*/ ) {
 191+ global $wgUser, $wgOut;
 192+ $args = func_get_args();
 193+ if ( wfReadOnly() ) {
 194+ return '<err#>' . wfMsgExt( 'revreview-failed', 'parseinline' ) .
 195+ wfMsgExt( 'revreview-submission-invalid', 'parseinline' );
 196+ }
 197+ $tags = FlaggedRevs::getTags();
 198+ // Make review interface object
 199+ $form = new RevisionReviewForm( $wgUser );
 200+ $title = null; // target page
 201+ $editToken = ''; // edit token
 202+ // Each ajax url argument is of the form param|val.
 203+ // This means that there is no ugly order dependance.
 204+ foreach ( $args as $arg ) {
 205+ $set = explode( '|', $arg, 2 );
 206+ if ( count( $set ) != 2 ) {
 207+ return '<err#>' . wfMsgExt( 'revreview-failed', 'parseinline' ) .
 208+ wfMsgExt( 'revreview-submission-invalid', 'parseinline' );
 209+ }
 210+ list( $par, $val ) = $set;
 211+ switch( $par )
 212+ {
 213+ case "target":
 214+ $title = Title::newFromURL( $val );
 215+ break;
 216+ case "oldid":
 217+ $form->setOldId( $val );
 218+ break;
 219+ case "refid":
 220+ $form->setRefId( $val );
 221+ break;
 222+ case "validatedParams":
 223+ $form->setValidatedParams( $val );
 224+ break;
 225+ case "templateParams":
 226+ $form->setTemplateParams( $val);
 227+ break;
 228+ case "imageParams":
 229+ $form->setFileParams( $val );
 230+ break;
 231+ case "fileVersion":
 232+ $form->setFileVersion( $val );
 233+ break;
 234+ case "wpApprove":
 235+ $form->setApprove( $val );
 236+ break;
 237+ case "wpUnapprove":
 238+ $form->setUnapprove( $val );
 239+ break;
 240+ case "wpReject":
 241+ $form->setReject( $val );
 242+ break;
 243+ case "wpReason":
 244+ $form->setComment( $val );
 245+ break;
 246+ case "changetime":
 247+ $form->setLastChangeTime( $val );
 248+ break;
 249+ case "wpEditToken":
 250+ $editToken = $val;
 251+ break;
 252+ default:
 253+ $p = preg_replace( '/^wp/', '', $par ); // kill any "wp" prefix
 254+ if ( in_array( $p, $tags ) ) {
 255+ $form->setDim( $p, $val );
 256+ }
 257+ break;
 258+ }
 259+ }
 260+ # Valid target title?
 261+ if ( !$title ) {
 262+ return '<err#>' . wfMsgExt( 'notargettext', 'parseinline' );
 263+ }
 264+ $form->setPage( $title );
 265+
 266+ $status = $form->ready(); // all params loaded
 267+ # Page must exist and be in reviewable namespace
 268+ if ( $status === 'review_page_unreviewable' ) {
 269+ return '<err#>' . wfMsgExt( 'revreview-main', 'parseinline' );
 270+ } elseif ( $status === 'review_page_notexists' ) {
 271+ return '<err#>' . wfMsgExt( 'nopagetext', 'parseinline' );
 272+ }
 273+ # Check session via user token
 274+ if ( !$wgUser->matchEditToken( $editToken ) ) {
 275+ return '<err#>' . wfMsgExt( 'sessionfailure', 'parseinline' );
 276+ }
 277+ # Basic permission checks...
 278+ $permErrors = $title->getUserPermissionsErrors( 'review', $wgUser, false );
 279+ if ( !$permErrors ) {
 280+ $permErrors = $title->getUserPermissionsErrors( 'edit', $wgUser, false );
 281+ }
 282+ if ( $permErrors ) {
 283+ return '<err#>' . $wgOut->parse(
 284+ $wgOut->formatPermissionsErrorMessage( $permErrors, 'review' )
 285+ );
 286+ }
 287+ # Try submission...
 288+ $status = $form->submit();
 289+ # Success...
 290+ if ( $status === true ) {
 291+ # Sent new lastChangeTime TS to client for later submissions...
 292+ $changeTime = $form->getNewLastChangeTime();
 293+ if ( $form->getAction() === 'approve' ) { // approve
 294+ return "<suc#><lct#$changeTime>";
 295+ } elseif ( $form->getAction() === 'unapprove' ) { // de-approve
 296+ return "<suc#><lct#$changeTime>";
 297+ } elseif ( $form->getAction() === 'reject' ) { // revert
 298+ return "<suc#><lct#$changeTime>";
 299+ }
 300+ # Failure...
 301+ } else {
 302+ return '<err#>' . wfMsgExt( 'revreview-failed', 'parse' ) .
 303+ '<p>' . wfMsgHtml( $status ) . '</p>';
 304+ }
 305+ }
 306+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/specialpages/actions/RevisionReview_body.php
___________________________________________________________________
Added: svn:eol-style
1307 + native
Index: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/PendingChanges_body.php
@@ -0,0 +1,437 @@
 2+<?php
 3+
 4+class PendingChanges extends SpecialPage {
 5+ protected $pager = null;
 6+
 7+ public function __construct() {
 8+ parent::__construct( 'PendingChanges' );
 9+ $this->includable( true );
 10+ }
 11+
 12+ public function execute( $par ) {
 13+ global $wgRequest, $wgUser;
 14+
 15+ $this->setHeaders();
 16+ $this->skin = $wgUser->getSkin();
 17+ $this->currentUnixTS = wfTimestamp( TS_UNIX ); // now
 18+
 19+ $this->namespace = $wgRequest->getIntOrNull( 'namespace' );
 20+ $this->level = $wgRequest->getInt( 'level', - 1 );
 21+ $category = trim( $wgRequest->getVal( 'category' ) );
 22+ $catTitle = Title::makeTitleSafe( NS_CATEGORY, $category );
 23+ $this->category = is_null( $catTitle ) ? '' : $catTitle->getText();
 24+ $this->size = $wgRequest->getIntOrNull( 'size' );
 25+ $this->watched = $wgRequest->getCheck( 'watched' );
 26+ $this->stable = $wgRequest->getCheck( 'stable' );
 27+ $feedType = $wgRequest->getVal( 'feed' );
 28+ if ( $this->including() ) {
 29+ $incLimit = $this->parseParams( $par ); // apply non-URL params
 30+ }
 31+
 32+ $this->pager = new PendingChangesPager( $this, $this->namespace,
 33+ $this->level, $this->category, $this->size, $this->watched, $this->stable );
 34+
 35+ # Output appropriate format...
 36+ if ( $feedType != null ) {
 37+ $this->feed( $feedType );
 38+ } else {
 39+ if ( $this->including() ) {
 40+ $this->pager->setLimit( $incLimit ); // apply non-URL limit
 41+ } else {
 42+ $this->setSyndicated();
 43+ $this->showForm();
 44+ }
 45+ $this->showPageList();
 46+ }
 47+ }
 48+
 49+ protected function setSyndicated() {
 50+ global $wgOut, $wgRequest;
 51+ $queryParams = array(
 52+ 'namespace' => $wgRequest->getIntOrNull( 'namespace' ),
 53+ 'level' => $wgRequest->getIntOrNull( 'level' ),
 54+ 'category' => $wgRequest->getVal( 'category' ),
 55+ );
 56+ $wgOut->setSyndicated( true );
 57+ $wgOut->setFeedAppendQuery( wfArrayToCGI( $queryParams ) );
 58+ }
 59+
 60+ public function showForm() {
 61+ global $wgUser, $wgOut, $wgScript, $wgLang;
 62+ # Explanatory text
 63+ $wgOut->addWikiMsg( 'pendingchanges-list',
 64+ $wgLang->formatNum( $this->pager->getNumRows() ) );
 65+
 66+ $form = Html::openElement( 'form', array( 'name' => 'pendingchanges',
 67+ 'action' => $wgScript, 'method' => 'get' ) ) . "\n";
 68+ $form .= "<fieldset><legend>" . wfMsgHtml( 'pendingchanges-legend' ) . "</legend>\n";
 69+ $form .= Html::hidden( 'title', $this->getTitle()->getPrefixedDBKey() ) . "\n";
 70+
 71+ $items = array();
 72+ if ( count( FlaggedRevs::getReviewNamespaces() ) > 1 ) {
 73+ $items[] = "<span style='white-space: nowrap;'>" .
 74+ FlaggedRevsXML::getNamespaceMenu( $this->namespace, '' ) . '</span>';
 75+ }
 76+ if ( FlaggedRevs::qualityVersions() ) {
 77+ $items[] = "<span style='white-space: nowrap;'>" .
 78+ FlaggedRevsXML::getLevelMenu( $this->level, 'revreview-filter-stable' ) .
 79+ '</span>';
 80+ }
 81+ if ( !FlaggedRevs::isStableShownByDefault() && !FlaggedRevs::useOnlyIfProtected() ) {
 82+ $items[] = "<span style='white-space: nowrap;'>" .
 83+ Xml::check( 'stable', $this->stable, array( 'id' => 'wpStable' ) ) .
 84+ Xml::label( wfMsg( 'pendingchanges-stable' ), 'wpStable' ) . '</span>';
 85+ }
 86+ if ( $items ) {
 87+ $form .= implode( ' ', $items ) . '<br />';
 88+ }
 89+
 90+ $items = array();
 91+ $items[] =
 92+ Xml::label( wfMsg( "pendingchanges-category" ), 'wpCategory' ) . '&#160;' .
 93+ Xml::input( 'category', 30, $this->category, array( 'id' => 'wpCategory' ) );
 94+ if ( $wgUser->getId() ) {
 95+ $items[] = Xml::check( 'watched', $this->watched, array( 'id' => 'wpWatched' ) ) .
 96+ Xml::label( wfMsg( 'pendingchanges-onwatchlist' ), 'wpWatched' );
 97+ }
 98+ $form .= implode( ' ', $items ) . '<br />';
 99+ $form .=
 100+ Xml::label( wfMsg( 'pendingchanges-size' ), 'wpSize' ) .
 101+ Xml::input( 'size', 4, $this->size, array( 'id' => 'wpSize' ) ) . ' ' .
 102+ Xml::submitButton( wfMsg( 'allpagessubmit' ) ) . "\n";
 103+ $form .= "</fieldset>";
 104+ $form .= Html::closeElement( 'form' ) . "\n";
 105+
 106+ $wgOut->addHTML( $form );
 107+ }
 108+
 109+ public function showPageList() {
 110+ global $wgOut;
 111+ // Viewing the list normally...
 112+ if ( !$this->including() ) {
 113+ if ( $this->pager->getNumRows() ) {
 114+ $wgOut->addHTML( $this->pager->getNavigationBar() );
 115+ $wgOut->addHTML( $this->pager->getBody() );
 116+ $wgOut->addHTML( $this->pager->getNavigationBar() );
 117+ } else {
 118+ $wgOut->addWikiMsg( 'pendingchanges-none' );
 119+ }
 120+ // If this list is transcluded...
 121+ } else {
 122+ if ( $this->pager->getNumRows() ) {
 123+ $wgOut->addHTML( $this->pager->getBody() );
 124+ } else {
 125+ $wgOut->addWikiMsg( 'pendingchanges-none' );
 126+ }
 127+ }
 128+ }
 129+
 130+ // set pager parameters from $par, return pager limit
 131+ protected function parseParams( $par ) {
 132+ global $wgLang;
 133+ $bits = preg_split( '/\s*,\s*/', trim( $par ) );
 134+ $limit = false;
 135+ foreach ( $bits as $bit ) {
 136+ if ( is_numeric( $bit ) ) {
 137+ $limit = intval( $bit );
 138+ }
 139+ $m = array();
 140+ if ( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) {
 141+ $limit = intval( $m[1] );
 142+ }
 143+ if ( preg_match( '/^namespace=(.*)$/', $bit, $m ) ) {
 144+ $ns = $wgLang->getNsIndex( $m[1] );
 145+ if ( $ns !== false ) {
 146+ $this->namespace = $ns;
 147+ }
 148+ }
 149+ if ( preg_match( '/^category=(.+)$/', $bit, $m ) ) {
 150+ $this->category = $m[1];
 151+ }
 152+ }
 153+ return $limit;
 154+ }
 155+
 156+ /**
 157+ * Output a subscription feed listing recent edits to this page.
 158+ * @param string $type
 159+ */
 160+ protected function feed( $type ) {
 161+ global $wgFeed, $wgFeedClasses, $wgFeedLimit, $wgOut;
 162+ if ( !$wgFeed ) {
 163+ $wgOut->addWikiMsg( 'feed-unavailable' );
 164+ return;
 165+ }
 166+ if ( !isset( $wgFeedClasses[$type] ) ) {
 167+ $wgOut->addWikiMsg( 'feed-invalid' );
 168+ return;
 169+ }
 170+ $feed = new $wgFeedClasses[$type](
 171+ $this->feedTitle(),
 172+ wfMsg( 'tagline' ),
 173+ $this->getTitle()->getFullUrl()
 174+ );
 175+ $this->pager->mLimit = min( $wgFeedLimit, $this->pager->mLimit );
 176+
 177+ $feed->outHeader();
 178+ if ( $this->pager->getNumRows() > 0 ) {
 179+ foreach ( $this->pager->mResult as $row ) {
 180+ $feed->outItem( $this->feedItem( $row ) );
 181+ }
 182+ }
 183+ $feed->outFooter();
 184+ }
 185+
 186+ protected function feedTitle() {
 187+ global $wgContLanguageCode, $wgSitename;
 188+ $page = SpecialPage::getPage( 'PendingChanges' );
 189+ $desc = $page->getDescription();
 190+ return "$wgSitename - $desc [$wgContLanguageCode]";
 191+ }
 192+
 193+ protected function feedItem( $row ) {
 194+ $title = Title::MakeTitle( $row->page_namespace, $row->page_title );
 195+ if ( $title ) {
 196+ $date = $row->pending_since;
 197+ $comments = $title->getTalkPage()->getFullURL();
 198+ $curRev = Revision::newFromTitle( $title );
 199+ return new FeedItem(
 200+ $title->getPrefixedText(),
 201+ FeedUtils::formatDiffRow( $title, $row->stable, $curRev->getId(),
 202+ $row->pending_since, $curRev->getComment() ),
 203+ $title->getFullURL(),
 204+ $date,
 205+ $curRev->getUserText(),
 206+ $comments );
 207+ } else {
 208+ return null;
 209+ }
 210+ }
 211+
 212+ public function formatRow( $row ) {
 213+ global $wgLang, $wgUser;
 214+ $css = $quality = $underReview = '';
 215+ $title = Title::newFromRow( $row );
 216+ $stxt = ChangesList::showCharacterDifference( $row->rev_len, $row->page_len );
 217+ # Page links...
 218+ $link = $this->skin->link( $title );
 219+ $hist = $this->skin->linkKnown( $title,
 220+ wfMsgHtml( 'hist' ), array(), 'action=history' );
 221+ $review = $this->skin->linkKnown( $title,
 222+ wfMsg( 'pendingchanges-diff' ),
 223+ array(),
 224+ 'diff=cur&oldid='.intval($row->stable).'&diffonly=0' );
 225+ # Show quality level if there are several
 226+ if ( FlaggedRevs::qualityVersions() ) {
 227+ $quality = $row->quality
 228+ ? wfMsgHtml( 'revreview-lev-quality' )
 229+ : wfMsgHtml( 'revreview-lev-basic' );
 230+ $quality = " <b>[{$quality}]</b>";
 231+ }
 232+ # Is anybody watching?
 233+ if ( !$this->including() && $wgUser->isAllowed( 'unreviewedpages' ) ) {
 234+ $uw = FRUserActivity::numUsersWatchingPage( $title );
 235+ $watching = $uw
 236+ ? wfMsgExt( 'pendingchanges-watched', 'parsemag', $wgLang->formatNum( $uw ) )
 237+ : wfMsgHtml( 'pendingchanges-unwatched' );
 238+ $watching = " {$watching}";
 239+ } else {
 240+ $uw = - 1;
 241+ $watching = ''; // leave out data
 242+ }
 243+ # Get how long the first unreviewed edit has been waiting...
 244+ if ( $row->pending_since ) {
 245+ $firstPendingTime = wfTimestamp( TS_UNIX, $row->pending_since );
 246+ $hours = ( $this->currentUnixTS - $firstPendingTime ) / 3600;
 247+ // After three days, just use days
 248+ if ( $hours > ( 3 * 24 ) ) {
 249+ $days = round( $hours / 24, 0 );
 250+ $age = wfMsgExt( 'pendingchanges-days',
 251+ 'parsemag', $wgLang->formatNum( $days ) );
 252+ // If one or more hours, use hours
 253+ } elseif ( $hours >= 1 ) {
 254+ $hours = round( $hours, 0 );
 255+ $age = wfMsgExt( 'pendingchanges-hours',
 256+ 'parsemag', $wgLang->formatNum( $hours ) );
 257+ } else {
 258+ $age = wfMsg( 'pendingchanges-recent' ); // hot off the press :)
 259+ }
 260+ // Oh-noes!
 261+ $css = self::getLineClass( $hours, $uw );
 262+ $css = $css ? " class='$css'" : "";
 263+ } else {
 264+ $age = ""; // wtf?
 265+ }
 266+ # Show if a user is looking at this page
 267+ list( $u, $ts ) = FRUserActivity::getUserReviewingDiff( $row->stable, $row->page_latest );
 268+ if ( $u !== null ) {
 269+ $underReview = ' <span class="fr-under-review">' .
 270+ wfMsgHtml( 'pendingchanges-viewing' ) . '</span>';
 271+ }
 272+
 273+ return( "<li{$css}>{$link} ({$hist}) {$stxt} ({$review}) <i>{$age}</i>" .
 274+ "{$quality}{$watching}{$underReview}</li>" );
 275+ }
 276+
 277+ protected static function getLineClass( $hours, $uw ) {
 278+ if ( $uw == 0 ) {
 279+ return 'fr-unreviewed-unwatched';
 280+ } else {
 281+ return "";
 282+ }
 283+ }
 284+}
 285+
 286+/**
 287+ * Query to list out outdated reviewed pages
 288+ */
 289+class PendingChangesPager extends AlphabeticPager {
 290+ public $mForm;
 291+ protected $category, $namespace;
 292+
 293+ const PAGE_LIMIT = 100; // Don't get too expensive
 294+
 295+ function __construct( $form, $namespace, $level = - 1, $category = '',
 296+ $size = null, $watched = false, $stable = false )
 297+ {
 298+ $this->mForm = $form;
 299+ # Must be a content page...
 300+ $vnamespaces = FlaggedRevs::getReviewNamespaces();
 301+ if ( is_null( $namespace ) ) {
 302+ $namespace = $vnamespaces;
 303+ } else {
 304+ $namespace = intval( $namespace );
 305+ }
 306+ # Sanity check
 307+ if ( !in_array( $namespace, $vnamespaces ) ) {
 308+ $namespace = $vnamespaces;
 309+ }
 310+ $this->namespace = $namespace;
 311+ # Sanity check level: 0 = checked; 1 = quality; 2 = pristine
 312+ $this->level = ( $level >= 0 && $level <= 2 ) ? $level : - 1;
 313+ $this->category = $category ? str_replace( ' ', '_', $category ) : null;
 314+ $this->size = ( $size !== null ) ? intval( $size ) : null;
 315+ $this->watched = (bool)$watched;
 316+ $this->stable = $stable && !FlaggedRevs::isStableShownByDefault()
 317+ && !FlaggedRevs::useOnlyIfProtected();
 318+
 319+ parent::__construct();
 320+ # Don't get too expensive
 321+ $this->mLimitsShown = array( 20, 50, 100 );
 322+ $this->setLimit( $this->mLimit ); // apply max limit
 323+ }
 324+
 325+ function setLimit( $limit ) {
 326+ $this->mLimit = min( $limit, self::PAGE_LIMIT );
 327+ }
 328+
 329+ function formatRow( $row ) {
 330+ return $this->mForm->formatRow( $row );
 331+ }
 332+
 333+ function getDefaultQuery() {
 334+ $query = parent::getDefaultQuery();
 335+ $query['category'] = $this->category;
 336+ return $query;
 337+ }
 338+
 339+ function getDefaultDirections() {
 340+ return false;
 341+ }
 342+
 343+ function getQueryInfo() {
 344+ global $wgUser;
 345+ $tables = array( 'page', 'revision' );
 346+ $fields = array( 'page_namespace', 'page_title', 'page_len', 'rev_len', 'page_latest' );
 347+ # Show outdated "stable" versions
 348+ if ( $this->level < 0 ) {
 349+ $tables[] = 'flaggedpages';
 350+ $fields[] = 'fp_stable AS stable';
 351+ $fields[] = 'fp_quality AS quality';
 352+ $fields[] = 'fp_pending_since AS pending_since';
 353+ $conds[] = 'page_id = fp_page_id';
 354+ $conds[] = 'rev_id = fp_stable'; // PK
 355+ $conds[] = 'fp_pending_since IS NOT NULL';
 356+ # Filter by pages configured to be stable
 357+ if ( $this->stable ) {
 358+ $tables[] = 'flaggedpage_config';
 359+ $conds[] = 'fp_page_id = fpc_page_id';
 360+ $conds['fpc_override'] = 1;
 361+ }
 362+ # Filter by category
 363+ if ( $this->category != '' ) {
 364+ $tables[] = 'categorylinks';
 365+ $conds[] = 'cl_from = fp_page_id';
 366+ $conds['cl_to'] = $this->category;
 367+ }
 368+ $this->mIndexField = 'fp_pending_since';
 369+ # Show outdated version for a specific review level
 370+ } else {
 371+ $tables[] = 'flaggedpage_pending';
 372+ $fields[] = 'fpp_rev_id AS stable';
 373+ $fields[] = 'fpp_quality AS quality';
 374+ $fields[] = 'fpp_pending_since AS pending_since';
 375+ $conds[] = 'page_id = fpp_page_id';
 376+ $conds[] = 'rev_id = fpp_rev_id'; // PK
 377+ $conds[] = 'fpp_pending_since IS NOT NULL';
 378+ # Filter by review level
 379+ $conds['fpp_quality'] = $this->level;
 380+ # Filter by pages configured to be stable
 381+ if ( $this->stable ) {
 382+ $tables[] = 'flaggedpage_config';
 383+ $conds[] = 'fpp_page_id = fpc_page_id';
 384+ $conds['fpc_override'] = 1;
 385+ }
 386+ # Filter by category
 387+ if ( $this->category != '' ) {
 388+ $tables[] = 'categorylinks';
 389+ $conds[] = 'cl_from = fpp_page_id';
 390+ $conds['cl_to'] = $this->category;
 391+ }
 392+ $this->mIndexField = 'fpp_pending_since';
 393+ }
 394+ $fields[] = $this->mIndexField; // Pager needs this
 395+ # Filter namespace
 396+ if ( $this->namespace !== null ) {
 397+ $conds['page_namespace'] = $this->namespace;
 398+ }
 399+ # Filter by watchlist
 400+ if ( $this->watched && ( $uid = $wgUser->getId() ) ) {
 401+ $tables[] = 'watchlist';
 402+ $conds[] = "wl_user = '$uid'";
 403+ $conds[] = 'page_namespace = wl_namespace';
 404+ $conds[] = 'page_title = wl_title';
 405+ }
 406+ # Filter by bytes changed
 407+ if ( $this->size !== null && $this->size >= 0 ) {
 408+ # Note: ABS(x-y) is broken due to mysql unsigned int design.
 409+ $conds[] = 'GREATEST(page_len,rev_len)-LEAST(page_len,rev_len) <= ' .
 410+ intval( $this->size );
 411+ }
 412+ return array(
 413+ 'tables' => $tables,
 414+ 'fields' => $fields,
 415+ 'conds' => $conds
 416+ );
 417+ }
 418+
 419+ function getIndexField() {
 420+ return $this->mIndexField;
 421+ }
 422+
 423+ function getStartBody() {
 424+ wfProfileIn( __METHOD__ );
 425+ # Do a link batch query
 426+ $lb = new LinkBatch();
 427+ foreach ( $this->mResult as $row ) {
 428+ $lb->add( $row->page_namespace, $row->page_title );
 429+ }
 430+ $lb->execute();
 431+ wfProfileOut( __METHOD__ );
 432+ return '<ul>';
 433+ }
 434+
 435+ function getEndBody() {
 436+ return '</ul>';
 437+ }
 438+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/PendingChanges_body.php
___________________________________________________________________
Added: svn:eol-style
1439 + native
Index: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/UnreviewedPages_body.php
@@ -0,0 +1,361 @@
 2+<?php
 3+
 4+class UnreviewedPages extends SpecialPage {
 5+ protected $pager = null;
 6+
 7+ public function __construct() {
 8+ parent::__construct( 'UnreviewedPages', 'unreviewedpages' );
 9+ }
 10+
 11+ public function execute( $par ) {
 12+ global $wgRequest, $wgUser, $wgOut;
 13+
 14+ $this->setHeaders();
 15+ if ( !$wgUser->isAllowed( 'unreviewedpages' ) ) {
 16+ $wgOut->permissionRequired( 'unreviewedpages' );
 17+ return;
 18+ }
 19+ $this->skin = $wgUser->getSkin();
 20+
 21+ # Get default namespace
 22+ $namespaces = FlaggedRevs::getReviewNamespaces();
 23+ $defaultNS = !$namespaces ? NS_MAIN : $namespaces[0];
 24+
 25+ $this->namespace = $wgRequest->getIntOrNull( 'namespace', $defaultNS );
 26+ $category = trim( $wgRequest->getVal( 'category' ) );
 27+ $catTitle = Title::makeTitleSafe( NS_CATEGORY, $category );
 28+ $this->category = is_null( $catTitle ) ? '' : $catTitle->getText();
 29+ $this->level = $wgRequest->getInt( 'level' );
 30+ $this->hideRedirs = $wgRequest->getBool( 'hideredirs', true );
 31+ $this->live = self::generalQueryOK();
 32+
 33+ $this->pager = new UnreviewedPagesPager( $this, $this->live,
 34+ $this->namespace, !$this->hideRedirs, $this->category, $this->level );
 35+
 36+ $this->showForm();
 37+ $this->showPageList();
 38+ }
 39+
 40+ protected function showForm() {
 41+ global $wgOut, $wgLang, $wgScript;
 42+ # Add explanatory text
 43+ $wgOut->addWikiMsg( 'unreviewedpages-list',
 44+ $wgLang->formatNum( $this->pager->getNumRows() ) );
 45+
 46+ # show/hide links
 47+ $showhide = array( wfMsgHtml( 'show' ), wfMsgHtml( 'hide' ) );
 48+ $onoff = 1 - $this->hideRedirs;
 49+ $link = $this->skin->link( $this->getTitle(), $showhide[$onoff], array(),
 50+ array( 'hideredirs' => $onoff, 'category' => $this->category,
 51+ 'namespace' => $this->namespace )
 52+ );
 53+ $showhideredirs = wfMsgHtml( 'whatlinkshere-hideredirs', $link );
 54+
 55+ # Add form...
 56+ $form = Html::openElement( 'form', array( 'name' => 'unreviewedpages',
 57+ 'action' => $wgScript, 'method' => 'get' ) ) . "\n";
 58+ $form .= "<fieldset><legend>" . wfMsg( 'unreviewedpages-legend' ) . "</legend>\n";
 59+ $form .= Html::hidden( 'title', $this->getTitle()->getPrefixedDBKey() ) . "\n";
 60+ # Add dropdowns as needed
 61+ if ( count( FlaggedRevs::getReviewNamespaces() ) > 1 ) {
 62+ $form .= FlaggedRevsXML::getNamespaceMenu( $this->namespace ) . '&#160;';
 63+ }
 64+ if ( FlaggedRevs::qualityVersions() ) {
 65+ $form .= FlaggedRevsXML::getLevelMenu( $this->level, false, 1 ) . '&#160;';
 66+ }
 67+ $form .=
 68+ "<span style='white-space: nowrap;'>" .
 69+ Xml::label( wfMsg( "unreviewedpages-category" ), 'category' ) . '&#160;' .
 70+ Xml::input( 'category', 30, $this->category, array( 'id' => 'category' ) ) .
 71+ '</span><br />';
 72+ $form .= $showhideredirs . '&#160;&#160;';
 73+ $form .= Xml::submitButton( wfMsg( 'allpagessubmit' ) );
 74+ $form .= '</fieldset>';
 75+ $form .= Html::closeElement( 'form' ) . "\n";
 76+
 77+ # Query may get too slow to be live...
 78+ if ( !$this->live ) {
 79+ $dbr = wfGetDB( DB_SLAVE );
 80+ $ts = $dbr->selectField( 'querycache_info', 'qci_timestamp',
 81+ array( 'qci_type' => 'fr_unreviewedpages' ), __METHOD__ );
 82+ if ( $ts ) {
 83+ $ts = wfTimestamp( TS_MW, $ts );
 84+ $td = $wgLang->timeanddate( $ts );
 85+ $d = $wgLang->date( $ts );
 86+ $t = $wgLang->time( $ts );
 87+ $form .= wfMsgExt( 'perfcachedts', 'parse', $td, $d, $t );
 88+ } else {
 89+ $form .= wfMsgExt( 'perfcached', 'parse' );
 90+ }
 91+ }
 92+
 93+ $wgOut->addHTML( $form );
 94+ }
 95+
 96+ protected function showPageList() {
 97+ global $wgOut;
 98+ if ( $this->pager->getNumRows() ) {
 99+ $wgOut->addHTML( $this->pager->getNavigationBar() );
 100+ $wgOut->addHTML( $this->pager->getBody() );
 101+ $wgOut->addHTML( $this->pager->getNavigationBar() );
 102+ } else {
 103+ $wgOut->addWikiMsg( 'unreviewedpages-none' );
 104+ }
 105+ }
 106+
 107+ public function formatRow( $row ) {
 108+ global $wgLang, $wgUser;
 109+ $title = Title::newFromRow( $row );
 110+
 111+ $stxt = $underReview = $watching = '';
 112+ $link = $this->skin->link( $title, null, array(), 'redirect=no&reviewing=1' );
 113+ $hist = $this->skin->linkKnown( $title, wfMsgHtml( 'hist' ),
 114+ array(), 'action=history&reviewing=1' );
 115+ if ( !is_null( $size = $row->page_len ) ) {
 116+ $stxt = ( $size == 0 )
 117+ ? wfMsgHtml( 'historyempty' )
 118+ : wfMsgExt( 'historysize', 'parsemag', $wgLang->formatNum( $size ) );
 119+ $stxt = " <small>$stxt</small>";
 120+ }
 121+ # Get how long the first unreviewed edit has been waiting...
 122+ static $currentTime;
 123+ $currentTime = wfTimestamp( TS_UNIX ); // now
 124+ $firstPendingTime = wfTimestamp( TS_UNIX, $row->creation );
 125+ $hours = ( $currentTime - $firstPendingTime ) / 3600;
 126+ // After three days, just use days
 127+ if ( $hours > ( 3 * 24 ) ) {
 128+ $days = round( $hours / 24, 0 );
 129+ $age = ' ' . wfMsgExt( 'unreviewedpages-days',
 130+ 'parsemag', $wgLang->formatNum( $days ) );
 131+ // If one or more hours, use hours
 132+ } elseif ( $hours >= 1 ) {
 133+ $hours = round( $hours, 0 );
 134+ $age = ' ' . wfMsgExt( 'unreviewedpages-hours',
 135+ 'parsemag', $wgLang->formatNum( $hours ) );
 136+ } else {
 137+ $age = ' ' . wfMsg( 'unreviewedpages-recent' ); // hot off the press :)
 138+ }
 139+ if ( $wgUser->isAllowed( 'unwatchedpages' ) ) {
 140+ $uw = FRUserActivity::numUsersWatchingPage( $title );
 141+ $watching = $uw
 142+ ? wfMsgExt( 'unreviewedpages-watched', 'parsemag', $wgLang->formatNum( $uw ) )
 143+ : wfMsgHtml( 'unreviewedpages-unwatched' );
 144+ $watching = " $watching"; // Oh-noes!
 145+ } else {
 146+ $uw = - 1;
 147+ }
 148+ $css = self::getLineClass( $hours, $uw );
 149+ $css = $css ? " class='$css'" : "";
 150+
 151+ # Show if a user is looking at this page
 152+ list( $u, $ts ) = FRUserActivity::getUserReviewingPage( $row->page_id );
 153+ if ( $u !== null ) {
 154+ $underReview = " <span class='fr-under-review'>" .
 155+ wfMsgHtml( 'unreviewedpages-viewing' ) . '</span>';
 156+ }
 157+
 158+ return( "<li{$css}>{$link} {$stxt} ({$hist})" .
 159+ "{$age}{$watching}{$underReview}</li>" );
 160+ }
 161+
 162+ protected static function getLineClass( $hours, $uw ) {
 163+ if ( $uw == 0 )
 164+ return 'fr-unreviewed-unwatched';
 165+ else if ( $hours > 20 * 24 )
 166+ return 'fr-pending-long2';
 167+ else if ( $hours > 7 * 24 )
 168+ return 'fr-pending-long';
 169+ else
 170+ return "";
 171+ }
 172+
 173+ /**
 174+ * There may be many pages, most of which are reviewed
 175+ */
 176+ public static function generalQueryOK() {
 177+ $namespaces = FlaggedRevs::getReviewNamespaces();
 178+ if ( !$namespaces || !wfQueriesMustScale() ) {
 179+ return true;
 180+ }
 181+ # Get est. of fraction of pages that are reviewed
 182+ $dbr = wfGetDB( DB_SLAVE );
 183+ $reviewedpages = $dbr->estimateRowCount( 'flaggedpages', '*', array(), __METHOD__ );
 184+ $pages = $dbr->estimateRowCount( 'page', '*',
 185+ array( 'page_namespace' => $namespaces ),
 186+ __METHOD__
 187+ );
 188+ $ratio = $pages / ( $pages - $reviewedpages );
 189+ # If dist. is equal, # of rows scanned = $ratio * LIMIT (or until list runs out)
 190+ return ( $ratio <= 400 );
 191+ }
 192+}
 193+
 194+/**
 195+ * Query to list out unreviewed pages
 196+ */
 197+class UnreviewedPagesPager extends AlphabeticPager {
 198+ public $mForm;
 199+ protected $live, $namespace, $category, $showredirs;
 200+
 201+ const PAGE_LIMIT = 50; // Don't get too expensive
 202+
 203+ function __construct(
 204+ $form, $live, $namespace, $redirs = false, $category = null, $level = 0
 205+ ) {
 206+ $this->mForm = $form;
 207+ $this->live = (bool)$live;
 208+ # Must be a content page...
 209+ if ( !is_null( $namespace ) ) {
 210+ $namespace = (int)$namespace;
 211+ }
 212+ $vnamespaces = FlaggedRevs::getReviewNamespaces();
 213+ # Must be a single NS for perfomance reasons
 214+ if ( is_null( $namespace ) || !in_array( $namespace, $vnamespaces ) ) {
 215+ $namespace = !$vnamespaces ? -1 : $vnamespaces[0];
 216+ }
 217+ $this->namespace = $namespace;
 218+ $this->category = $category ? str_replace( ' ', '_', $category ) : null;
 219+ $this->level = intval( $level );
 220+ $this->showredirs = (bool)$redirs;
 221+ parent::__construct();
 222+ // Don't get too expensive
 223+ $this->mLimitsShown = array( 20, 50 );
 224+ $this->setLimit( $this->mLimit ); // apply max limit
 225+ }
 226+
 227+ function setLimit( $limit ) {
 228+ $this->mLimit = min( $limit, self::PAGE_LIMIT );
 229+ }
 230+
 231+ function formatRow( $row ) {
 232+ return $this->mForm->formatRow( $row );
 233+ }
 234+
 235+ function getQueryInfo() {
 236+ if ( !$this->live ) {
 237+ return $this->getQueryCacheInfo();
 238+ }
 239+ $fields = array( 'page_namespace', 'page_title', 'page_len', 'page_id',
 240+ 'MIN(rev_timestamp) AS creation' );
 241+ # Filter by level
 242+ if ( $this->level == 1 ) {
 243+ $conds[] = "fp_page_id IS NULL OR fp_quality = 0";
 244+ } else {
 245+ $conds[] = 'fp_page_id IS NULL';
 246+ }
 247+ # Reviewable pages only
 248+ $conds['page_namespace'] = $this->namespace;
 249+ # No redirects
 250+ if ( !$this->showredirs ) {
 251+ $conds['page_is_redirect'] = 0;
 252+ }
 253+ # Filter by category
 254+ if ( $this->category != '' ) {
 255+ $tables = array( 'categorylinks', 'page', 'flaggedpages', 'revision' );
 256+ $fields[] = 'cl_sortkey';
 257+ $conds['cl_to'] = $this->category;
 258+ $conds[] = 'cl_from = page_id';
 259+ # Note: single NS always specified
 260+ if ( $this->namespace == NS_FILE ) {
 261+ $conds['cl_type'] = 'file';
 262+ } elseif ( $this->namespace == NS_CATEGORY ) {
 263+ $conds['cl_type'] = 'subcat';
 264+ } else {
 265+ $conds['cl_type'] = 'page';
 266+ }
 267+ $this->mIndexField = 'cl_sortkey';
 268+ $useIndex = array( 'categorylinks' => 'cl_sortkey' );
 269+ $groupBy = 'cl_sortkey,cl_from';
 270+ } else {
 271+ $tables = array( 'page', 'flaggedpages', 'revision' );
 272+ $this->mIndexField = 'page_title';
 273+ $useIndex = array( 'page' => 'name_title' );
 274+ $groupBy = 'page_title';
 275+ }
 276+ $useIndex['revision'] = 'page_timestamp'; // sigh...
 277+ return array(
 278+ 'tables' => $tables,
 279+ 'fields' => $fields,
 280+ 'conds' => $conds,
 281+ 'options' => array( 'USE INDEX' => $useIndex, 'GROUP BY' => $groupBy ),
 282+ 'join_conds' => array(
 283+ 'revision' => array( 'LEFT JOIN', 'rev_page=page_id' ), // Get creation date
 284+ 'flaggedpages' => array( 'LEFT JOIN', 'fp_page_id=page_id' )
 285+ )
 286+ );
 287+ }
 288+
 289+ function getQueryCacheInfo() {
 290+ $conds = $this->mConds;
 291+ $fields = array( 'page_namespace', 'page_title', 'page_len', 'page_id',
 292+ 'qc_value', 'MIN(rev_timestamp) AS creation' );
 293+ # Re-join on flaggedpages to double-check since things
 294+ # could have changed since the cache date. Also, use
 295+ # the proper cache for this level.
 296+ if ( $this->level == 1 ) {
 297+ $conds['qc_type'] = 'fr_unreviewedpages_q';
 298+ $conds[] = "fp_page_id IS NULL OR fp_quality < 1";
 299+ } else {
 300+ $conds['qc_type'] = 'fr_unreviewedpages';
 301+ $conds[] = 'fp_page_id IS NULL';
 302+ }
 303+ # Reviewable pages only
 304+ $conds['qc_namespace'] = $this->namespace;
 305+ # No redirects
 306+ if ( !$this->showredirs ) {
 307+ $conds['page_is_redirect'] = 0;
 308+ }
 309+ $this->mIndexField = 'qc_value'; // page_id
 310+ # Filter by category
 311+ if ( $this->category != '' ) {
 312+ $tables = array( 'page', 'categorylinks', 'querycache', 'flaggedpages', 'revision' );
 313+ $conds['cl_to'] = $this->category;
 314+ $conds[] = 'cl_from = qc_value'; // page_id
 315+ # Note: single NS always specified
 316+ if ( $this->namespace == NS_FILE ) {
 317+ $conds['cl_type'] = 'file';
 318+ } elseif ( $this->namespace == NS_CATEGORY ) {
 319+ $conds['cl_type'] = 'subcat';
 320+ } else {
 321+ $conds['cl_type'] = 'page';
 322+ }
 323+ } else {
 324+ $tables = array( 'page', 'querycache', 'flaggedpages', 'revision' );
 325+ }
 326+ $useIndex = array( 'querycache' => 'qc_type', 'page' => 'PRIMARY',
 327+ 'revision' => 'page_timestamp' ); // sigh...
 328+ return array(
 329+ 'tables' => $tables,
 330+ 'fields' => $fields,
 331+ 'conds' => $conds,
 332+ 'options' => array( 'USE INDEX' => $useIndex, 'GROUP BY' => 'qc_value' ),
 333+ 'join_conds' => array(
 334+ 'querycache' => array( 'LEFT JOIN', 'qc_value=page_id' ),
 335+ 'revision' => array( 'LEFT JOIN', 'rev_page=page_id' ), // Get creation date
 336+ 'flaggedpages' => array( 'LEFT JOIN', 'fp_page_id=page_id' ),
 337+ 'categorylinks' => array( 'LEFT JOIN',
 338+ array( 'cl_from=page_id', 'cl_to' => $this->category ) )
 339+ )
 340+ );
 341+ }
 342+
 343+ function getIndexField() {
 344+ return $this->mIndexField;
 345+ }
 346+
 347+ function getStartBody() {
 348+ wfProfileIn( __METHOD__ );
 349+ # Do a link batch query
 350+ $lb = new LinkBatch();
 351+ foreach ( $this->mResult as $row ) {
 352+ $lb->add( $row->page_namespace, $row->page_title );
 353+ }
 354+ $lb->execute();
 355+ wfProfileOut( __METHOD__ );
 356+ return '<ul>';
 357+ }
 358+
 359+ function getEndBody() {
 360+ return '</ul>';
 361+ }
 362+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/UnreviewedPages_body.php
___________________________________________________________________
Added: svn:eol-style
1363 + native
Index: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/QualityOversight_body.php
@@ -0,0 +1,145 @@
 2+<?php
 3+
 4+class QualityOversight extends SpecialPage {
 5+ public function __construct() {
 6+ parent::__construct( 'QualityOversight' );
 7+ }
 8+
 9+ public function execute( $par ) {
 10+ global $wgOut, $wgUser, $wgRequest, $wgLang, $wgFlaggedRevsOversightAge;
 11+
 12+ $this->setHeaders();
 13+
 14+ $this->namespace = $wgRequest->getInt( 'namespace' );
 15+ $this->level = $wgRequest->getIntOrNull( 'level' );
 16+ $this->status = $wgRequest->getIntOrNull( 'status' );
 17+ $this->automatic = $wgRequest->getIntOrNull( 'automatic' );
 18+ $this->user = $wgRequest->getVal( 'user' );
 19+ # Check if the user exists
 20+ $usertitle = Title::makeTitleSafe( NS_USER, $this->user );
 21+ $u = $usertitle ? User::idFromName( $this->user ) : false;
 22+
 23+ # Are the dropdown params given even valid?
 24+ $actions = $this->getActions();
 25+ if ( empty( $actions ) ) {
 26+ $wgOut->addWikiMsg( 'qualityoversight-list', 0 );
 27+ $wgOut->addWikiMsg( 'logempty' );
 28+ return;
 29+ }
 30+
 31+ # Get extra query conds
 32+ $conds = array( 'log_namespace' => $this->namespace, 'log_action' => $actions );
 33+ # Get cutoff time (mainly for performance)
 34+ if ( !$u ) {
 35+ $dbr = wfGetDB( DB_SLAVE );
 36+ $cutoff_unixtime = time() - $wgFlaggedRevsOversightAge;
 37+ $cutoff = $dbr->addQuotes( $dbr->timestamp( $cutoff_unixtime ) );
 38+ $conds[] = "log_timestamp >= $cutoff";
 39+ }
 40+
 41+ # Create a LogPager item to get the results and a LogEventsList item to format them...
 42+ $loglist = new LogEventsList( $wgUser->getSkin(), $wgOut, 0 );
 43+ $pager = new LogPager( $loglist, 'review', $this->user, '', '', $conds );
 44+
 45+ # Explanatory text
 46+ $wgOut->addWikiMsg( 'qualityoversight-list',
 47+ $wgLang->formatNum( $pager->getNumRows() ) );
 48+ # Show form options
 49+ $this->showForm();
 50+
 51+ # Insert list
 52+ $logBody = $pager->getBody();
 53+ if ( $logBody ) {
 54+ $wgOut->addHTML(
 55+ $pager->getNavigationBar() .
 56+ $loglist->beginLogEventsList() .
 57+ $logBody .
 58+ $loglist->endLogEventsList() .
 59+ $pager->getNavigationBar()
 60+ );
 61+ } else {
 62+ $wgOut->addWikiMsg( 'logempty' );
 63+ }
 64+ }
 65+
 66+ private function showForm() {
 67+ global $wgOut, $wgScript;
 68+ $wgOut->addHTML(
 69+ Xml::openElement( 'form', array( 'name' => 'qualityoversight',
 70+ 'action' => $wgScript, 'method' => 'get' ) ) .
 71+ '<fieldset><legend>' . wfMsgHtml( 'qualityoversight-legend' ) . '</legend><p>' .
 72+ Html::hidden( 'title', $this->getTitle()->getPrefixedDBKey() ) .
 73+ FlaggedRevsXML::getNamespaceMenu( $this->namespace ) . '&#160;' .
 74+ ( FlaggedRevs::qualityVersions()
 75+ ? FlaggedRevsXML::getLevelMenu( $this->level, 'revreview-filter-all', 1 ) .
 76+ '&#160;'
 77+ : ""
 78+ ) .
 79+ Xml::inputLabel( wfMsg( 'specialloguserlabel' ), 'user', 'user', 20, $this->user ) .
 80+ '<br />' .
 81+ FlaggedRevsXML::getStatusFilterMenu( $this->status ) . '&#160;' .
 82+ FlaggedRevsXML::getAutoFilterMenu( $this->automatic ) . '&#160;' .
 83+ Xml::submitButton( wfMsg( 'go' ) ) .
 84+ '</p></fieldset>' . Xml::closeElement( 'form' )
 85+ );
 86+ }
 87+
 88+ /*
 89+ * Get actions for IN clause
 90+ * @returns array
 91+ */
 92+ private function getActions() {
 93+ $actions = array(
 94+ 'approve' => 1, 'approve2' => 1, 'approve-a' => 1, 'approve-i' => 1,
 95+ 'approve-ia' => 1, 'approve2-i' => 1, 'unapprove' => 1, 'unapprove2' => 1
 96+ );
 97+ if ( $this->level === 0 ) { // checked revisions
 98+ $actions['approve2'] = 0;
 99+ $actions['approve2-i'] = 0;
 100+ $actions['unapprove2'] = 0;
 101+ } elseif ( $this->level === 1 ) { // quality revisions
 102+ $actions['approve'] = 0;
 103+ $actions['approve-a'] = 0;
 104+ $actions['approve-i'] = 0;
 105+ $actions['approve-ia'] = 0;
 106+ $actions['unapprove'] = 0;
 107+ }
 108+ if ( $this->status === 1 ) { // approved first time
 109+ $actions['approve'] = 0;
 110+ $actions['approve-a'] = 0;
 111+ $actions['approve2'] = 0;
 112+ $actions['unapprove'] = 0;
 113+ $actions['unapprove2'] = 0;
 114+ } elseif ( $this->status === 2 ) { // re-approved
 115+ $actions['approve-i'] = 0;
 116+ $actions['approve-ia'] = 0;
 117+ $actions['approve2-i'] = 0;
 118+ $actions['unapprove'] = 0;
 119+ $actions['unapprove2'] = 0;
 120+ } elseif ( $this->status === 3 ) { // depreciated
 121+ $actions['approve'] = 0;
 122+ $actions['approve-a'] = 0;
 123+ $actions['approve-i'] = 0;
 124+ $actions['approve-ia'] = 0;
 125+ $actions['approve2'] = 0;
 126+ $actions['approve2-i'] = 0;
 127+ }
 128+ if ( $this->automatic === 0 ) { // manual review
 129+ $actions['approve-a'] = 0;
 130+ $actions['approve-ia'] = 0;
 131+ } elseif ( $this->automatic === 1 ) { // auto-reviewed
 132+ $actions['approve'] = 0;
 133+ $actions['approve-i'] = 0;
 134+ $actions['approve2'] = 0;
 135+ $actions['approve2-i'] = 0;
 136+ $actions['unapprove'] = 0;
 137+ $actions['unapprove2'] = 0;
 138+ }
 139+ $showActions = array();
 140+ foreach ( $actions as $action => $show ) {
 141+ if ( $show )
 142+ $showActions[] = $action;
 143+ }
 144+ return $showActions;
 145+ }
 146+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/QualityOversight_body.php
___________________________________________________________________
Added: svn:eol-style
1147 + native
Index: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/ReviewedVersions_body.php
@@ -0,0 +1,111 @@
 2+<?php
 3+
 4+class ReviewedVersions extends UnlistedSpecialPage {
 5+ public function __construct() {
 6+ parent::__construct( 'ReviewedVersions' );
 7+ }
 8+
 9+ public function execute( $par ) {
 10+ global $wgRequest, $wgUser, $wgOut;
 11+
 12+ $this->setHeaders();
 13+ $this->skin = $wgUser->getSkin();
 14+ # Our target page
 15+ $this->target = $wgRequest->getText( 'page' );
 16+ $this->page = Title::newFromURL( $this->target );
 17+ # Revision ID
 18+ $this->oldid = $wgRequest->getVal( 'oldid' );
 19+ $this->oldid = ( $this->oldid == 'best' ) ? 'best' : intval( $this->oldid );
 20+ # We need a page...
 21+ if ( is_null( $this->page ) ) {
 22+ $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
 23+ return;
 24+ }
 25+
 26+ $this->showStableList();
 27+ }
 28+
 29+ protected function showStableList() {
 30+ global $wgOut, $wgLang;
 31+ # Must be a content page
 32+ if ( !FlaggedRevs::inReviewNamespace( $this->page ) ) {
 33+ $wgOut->addWikiMsg( 'reviewedversions-none', $this->page->getPrefixedText() );
 34+ return;
 35+ }
 36+ $pager = new ReviewedVersionsPager( $this, array(), $this->page );
 37+ $num = $pager->getNumRows();
 38+ if ( $num ) {
 39+ $wgOut->addWikiMsg( 'reviewedversions-list',
 40+ $this->page->getPrefixedText(), $wgLang->formatNum( $num ) );
 41+ $wgOut->addHTML( $pager->getNavigationBar() );
 42+ $wgOut->addHTML( "<ul>" . $pager->getBody() . "</ul>" );
 43+ $wgOut->addHTML( $pager->getNavigationBar() );
 44+ } else {
 45+ $wgOut->addHTML( wfMsgExt( 'reviewedversions-none', array( 'parse' ),
 46+ $this->page->getPrefixedText() ) );
 47+ }
 48+ }
 49+
 50+ public function formatRow( $row ) {
 51+ global $wgLang;
 52+ $rdatim = $wgLang->timeanddate( wfTimestamp( TS_MW, $row->rev_timestamp ), true );
 53+ $fdatim = $wgLang->timeanddate( wfTimestamp( TS_MW, $row->fr_timestamp ), true );
 54+ $fdate = $wgLang->date( wfTimestamp( TS_MW, $row->fr_timestamp ), true );
 55+ $ftime = $wgLang->time( wfTimestamp( TS_MW, $row->fr_timestamp ), true );
 56+ $review = wfMsgExt( 'reviewedversions-review', array( 'parseinline', 'replaceafter' ),
 57+ $fdatim,
 58+ $this->skin->userLink( $row->fr_user, $row->user_name ) .
 59+ ' ' . $this->skin->userToolLinks( $row->fr_user, $row->user_name ),
 60+ $fdate, $ftime, $row->user_name
 61+ );
 62+ $lev = ( $row->fr_quality >= 1 )
 63+ ? wfMsgHtml( 'revreview-hist-quality' )
 64+ : wfMsgHtml( 'revreview-hist-basic' );
 65+ $link = $this->skin->makeKnownLinkObj( $this->page, $rdatim,
 66+ 'stableid=' . $row->fr_rev_id );
 67+ return '<li>' . $link . ' (' . $review . ') <strong>[' . $lev . ']</strong></li>';
 68+ }
 69+}
 70+
 71+/**
 72+ * Query to list out stable versions for a page
 73+ */
 74+class ReviewedVersionsPager extends ReverseChronologicalPager {
 75+ public $mForm, $mConds;
 76+
 77+ function __construct( $form, $conds = array(), $title ) {
 78+ $this->mForm = $form;
 79+ $this->mConds = $conds;
 80+ $this->namespace = $title->getNamespace();
 81+ $this->pageID = $title->getArticleID();
 82+
 83+ parent::__construct();
 84+ }
 85+
 86+ function formatRow( $row ) {
 87+ return $this->mForm->formatRow( $row );
 88+ }
 89+
 90+ function getQueryInfo() {
 91+ $conds = $this->mConds;
 92+ # Must be in a reviewable namespace
 93+ $namespaces = FlaggedRevs::getReviewNamespaces();
 94+ if ( !in_array( $this->namespace, $namespaces ) ) {
 95+ $conds[] = "1 = 0";
 96+ }
 97+ $conds["fr_page_id"] = $this->pageID;
 98+ $conds[] = "fr_rev_id = rev_id";
 99+ $conds[] = "fr_user = user_id";
 100+ $conds[] = 'rev_deleted & ' . Revision::DELETED_TEXT . ' = 0';
 101+ return array(
 102+ 'tables' => array( 'flaggedrevs', 'revision', 'user' ),
 103+ 'fields' => 'fr_rev_id,fr_timestamp,rev_timestamp,fr_quality,fr_user,user_name',
 104+ 'conds' => $conds,
 105+ 'options' => array( 'USE INDEX' => array( 'flaggedrevs' => 'PRIMARY' ) )
 106+ );
 107+ }
 108+
 109+ function getIndexField() {
 110+ return 'fr_rev_id';
 111+ }
 112+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/ReviewedVersions_body.php
___________________________________________________________________
Added: svn:eol-style
1113 + native
Index: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/ConfiguredPages_body.php
@@ -0,0 +1,195 @@
 2+<?php
 3+
 4+// Assumes $wgFlaggedRevsProtection is off
 5+class ConfiguredPages extends SpecialPage {
 6+ protected $pager = null;
 7+
 8+ public function __construct() {
 9+ parent::__construct( 'ConfiguredPages' );
 10+ }
 11+
 12+ public function execute( $par ) {
 13+ global $wgRequest, $wgUser;
 14+
 15+ $this->setHeaders();
 16+ $this->skin = $wgUser->getSkin();
 17+
 18+ $this->namespace = $wgRequest->getIntOrNull( 'namespace' );
 19+ $this->override = $wgRequest->getIntOrNull( 'stable' );
 20+ $this->autoreview = $wgRequest->getVal( 'restriction', '' );
 21+
 22+ $this->pager = new ConfiguredPagesPager(
 23+ $this, array(), $this->namespace, $this->override, $this->autoreview );
 24+
 25+ $this->showForm();
 26+ $this->showPageList();
 27+ }
 28+
 29+ protected function showForm() {
 30+ global $wgOut, $wgScript, $wgLang;
 31+ # Explanatory text
 32+ $wgOut->addWikiMsg( 'configuredpages-list',
 33+ $wgLang->formatNum( $this->pager->getNumRows() ) );
 34+
 35+ $fields = array();
 36+ # Namespace selector
 37+ if ( count( FlaggedRevs::getReviewNamespaces() ) > 1 ) {
 38+ $fields[] = FlaggedRevsXML::getNamespaceMenu( $this->namespace, '' );
 39+ }
 40+ # Default version selector
 41+ $fields[] = FlaggedRevsXML::getDefaultFilterMenu( $this->override );
 42+ # Restriction level selector
 43+ if ( FlaggedRevs::getRestrictionLevels() ) {
 44+ $fields[] = FlaggedRevsXML::getRestrictionFilterMenu( $this->autoreview );
 45+ }
 46+
 47+ $form = Html::openElement( 'form',
 48+ array( 'name' => 'configuredpages', 'action' => $wgScript, 'method' => 'get' ) );
 49+ $form .= Html::hidden( 'title', $this->getTitle()->getPrefixedDBKey() );
 50+ $form .= "<fieldset><legend>" . wfMsg( 'configuredpages' ) . "</legend>\n";
 51+ $form .= implode( '&#160;', $fields ) . '<br/>';
 52+ $form .= Xml::submitButton( wfMsg( 'go' ) );
 53+ $form .= "</fieldset>\n";
 54+ $form .= Html::closeElement( 'form' ) . "\n";
 55+
 56+ $wgOut->addHTML( $form );
 57+ }
 58+
 59+ protected function showPageList() {
 60+ global $wgOut;
 61+ if ( $this->pager->getNumRows() ) {
 62+ $wgOut->addHTML( $this->pager->getNavigationBar() );
 63+ $wgOut->addHTML( $this->pager->getBody() );
 64+ $wgOut->addHTML( $this->pager->getNavigationBar() );
 65+ } else {
 66+ $wgOut->addWikiMsg( 'configuredpages-none' );
 67+ }
 68+ # Purge expired entries on one in every 10 queries
 69+ if ( !mt_rand( 0, 10 ) ) {
 70+ FlaggedPageConfig::purgeExpiredConfigurations();
 71+ }
 72+ }
 73+
 74+ public function formatRow( $row ) {
 75+ global $wgLang;
 76+ $title = Title::newFromRow( $row );
 77+ # Link to page
 78+ $link = $this->skin->link( $title );
 79+ # Link to page configuration
 80+ $config = $this->skin->linkKnown(
 81+ SpecialPage::getTitleFor( 'Stabilization' ),
 82+ wfMsgHtml( 'configuredpages-config' ),
 83+ array(),
 84+ 'page=' . $title->getPrefixedUrl()
 85+ );
 86+ # Show which version is the default (stable or draft)
 87+ if ( intval( $row->fpc_override ) ) {
 88+ $default = wfMsgHtml( 'configuredpages-def-stable' );
 89+ } else {
 90+ $default = wfMsgHtml( 'configuredpages-def-draft' );
 91+ }
 92+ # Autoreview/review restriction level
 93+ $restr = '';
 94+ if ( $row->fpc_level != '' ) {
 95+ $restr = 'autoreview=' . htmlspecialchars( $row->fpc_level );
 96+ $restr = "[$restr]";
 97+ }
 98+ # When these configuration settings expire
 99+ if ( $row->fpc_expiry != 'infinity' && strlen( $row->fpc_expiry ) ) {
 100+ $expiry_description = " (" . wfMsgForContent(
 101+ 'protect-expiring',
 102+ $wgLang->timeanddate( $row->fpc_expiry ),
 103+ $wgLang->date( $row->fpc_expiry ),
 104+ $wgLang->time( $row->fpc_expiry )
 105+ ) . ")";
 106+ } else {
 107+ $expiry_description = "";
 108+ }
 109+ return "<li>{$link} ({$config}) <b>[$default]</b> " .
 110+ "{$restr}<i>{$expiry_description}</i></li>";
 111+ }
 112+}
 113+
 114+/**
 115+ * Query to list out stable versions for a page
 116+ */
 117+class ConfiguredPagesPager extends AlphabeticPager {
 118+ public $mForm, $mConds, $namespace, $override, $autoreview;
 119+
 120+ /*
 121+ * @param int $namespace (null for "all")
 122+ * @param int $override (null for "either")
 123+ * @param string $autoreview ('' for "all", 'none' for no restriction)
 124+ */
 125+ function __construct( $form, $conds = array(), $namespace, $override, $autoreview ) {
 126+ $this->mForm = $form;
 127+ $this->mConds = $conds;
 128+ # Must be content pages...
 129+ $validNS = FlaggedRevs::getReviewNamespaces();
 130+ if ( is_integer( $namespace ) ) {
 131+ if ( !in_array( $namespace, $validNS ) ) {
 132+ $namespace = $validNS; // fallback to "all"
 133+ }
 134+ } else {
 135+ $namespace = $validNS; // "all"
 136+ }
 137+ $this->namespace = $namespace;
 138+ if ( !is_integer( $override ) ) {
 139+ $override = null; // "all"
 140+ }
 141+ $this->override = $override;
 142+ if ( $autoreview === 'none' ) {
 143+ $autoreview = ''; // 'none' => ''
 144+ } elseif ( $autoreview === '' ) {
 145+ $autoreview = null; // '' => null
 146+ }
 147+ $this->autoreview = $autoreview;
 148+ parent::__construct();
 149+ }
 150+
 151+ function formatRow( $row ) {
 152+ return $this->mForm->formatRow( $row );
 153+ }
 154+
 155+ function getQueryInfo() {
 156+ $conds = $this->mConds;
 157+ $conds[] = 'page_id = fpc_page_id';
 158+ if ( $this->override !== null ) {
 159+ $conds['fpc_override'] = $this->override;
 160+ }
 161+ if ( $this->autoreview !== null ) {
 162+ $conds['fpc_level'] = $this->autoreview;
 163+ }
 164+ $conds['page_namespace'] = $this->namespace;
 165+ # Be sure not to include expired items
 166+ $encCutoff = $this->mDb->addQuotes( $this->mDb->timestamp() );
 167+ $conds[] = "fpc_expiry > {$encCutoff}";
 168+ return array(
 169+ 'tables' => array( 'flaggedpage_config', 'page' ),
 170+ 'fields' => array( 'page_namespace', 'page_title', 'fpc_override',
 171+ 'fpc_expiry', 'fpc_page_id', 'fpc_level' ),
 172+ 'conds' => $conds,
 173+ 'options' => array()
 174+ );
 175+ }
 176+
 177+ function getIndexField() {
 178+ return 'fpc_page_id';
 179+ }
 180+
 181+ function getStartBody() {
 182+ wfProfileIn( __METHOD__ );
 183+ # Do a link batch query
 184+ $lb = new LinkBatch();
 185+ foreach ( $this->mResult as $row ) {
 186+ $lb->add( $row->page_namespace, $row->page_title );
 187+ }
 188+ $lb->execute();
 189+ wfProfileOut( __METHOD__ );
 190+ return '<ul>';
 191+ }
 192+
 193+ function getEndBody() {
 194+ return '</ul>';
 195+ }
 196+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/ConfiguredPages_body.php
___________________________________________________________________
Added: svn:eol-style
1197 + native
Index: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/ValidationStatistics_body.php
@@ -0,0 +1,274 @@
 2+<?php
 3+
 4+class ValidationStatistics extends IncludableSpecialPage {
 5+ public function __construct() {
 6+ parent::__construct( 'ValidationStatistics' );
 7+ }
 8+
 9+ public function execute( $par ) {
 10+ global $wgUser, $wgOut, $wgLang, $wgContLang, $wgFlaggedRevsStats;
 11+ $this->setHeaders();
 12+ $this->skin = $wgUser->getSkin();
 13+ $this->db = wfGetDB( DB_SLAVE );
 14+
 15+ $this->maybeUpdate();
 16+
 17+ $ec = $this->getEditorCount();
 18+ $rc = $this->getReviewerCount();
 19+ $mt = $this->getMeanReviewWait();
 20+ $mdt = $this->getMedianReviewWait();
 21+ $pt = $this->getMeanPendingWait();
 22+ $timestamp = $this->getLastUpdate();
 23+
 24+ $wgOut->addWikiMsg( 'validationstatistics-users',
 25+ $wgLang->formatnum( $ec ), $wgLang->formatnum( $rc )
 26+ );
 27+ # Most of the output depends on background queries
 28+ if ( !$this->readyForQuery() ) {
 29+ return false;
 30+ }
 31+
 32+ $key = wfMemcKey( 'flaggedrevs', 'reviewPercentiles' );
 33+ $dbCache = wfGetCache( CACHE_DB );
 34+ $data = $dbCache->get( $key );
 35+ # Is there a review time table available?
 36+ if ( is_array( $data ) && count( $data ) ) {
 37+ $headerRows = $dataRows = '';
 38+ foreach ( $data as $percentile => $perValue ) {
 39+ $headerRows .= "<th>P<sub>" . intval( $percentile ) . "</sub></th>";
 40+ $dataRows .= '<td>' . $wgLang->formatTimePeriod( $perValue ) . '</td>';
 41+ }
 42+ $css = 'wikitable flaggedrevs_stats_table';
 43+ $reviewChart = "<table class='$css' style='white-space: nowrap;'>\n";
 44+ $reviewChart .= "<tr align='center'>$headerRows</tr>\n";
 45+ $reviewChart .= "<tr align='center'>$dataRows</tr>\n";
 46+ $reviewChart .= "</table>\n";
 47+ } else {
 48+ $reviewChart = '';
 49+ }
 50+
 51+ if ( $timestamp != '-' ) {
 52+ # Show "last updated"...
 53+ $wgOut->addWikiMsg( 'validationstatistics-lastupdate',
 54+ $wgLang->date( $timestamp, true ),
 55+ $wgLang->time( $timestamp, true )
 56+ );
 57+ }
 58+ $wgOut->addHtml( '<hr/>' );
 59+ # Show pending time stats...
 60+ $wgOut->addWikiMsg( 'validationstatistics-pndtime', $wgLang->formatTimePeriod( $pt ) );
 61+ # Show review time stats...
 62+ if ( !FlaggedRevs::useOnlyIfProtected() ) {
 63+ $wgOut->addWikiMsg( 'validationstatistics-revtime',
 64+ $wgLang->formatTimePeriod( $mt ),
 65+ $wgLang->formatTimePeriod( $mdt ),
 66+ $reviewChart
 67+ );
 68+ }
 69+ # Show per-namespace stats table...
 70+ $wgOut->addWikiMsg( 'validationstatistics-table' );
 71+ $wgOut->addHTML(
 72+ Xml::openElement( 'table', array( 'class' => 'wikitable flaggedrevs_stats_table' ) )
 73+ );
 74+ $wgOut->addHTML( "<tr>\n" );
 75+ // Headings (for a positive grep result):
 76+ // validationstatistics-ns, validationstatistics-total, validationstatistics-stable,
 77+ // validationstatistics-latest, validationstatistics-synced, validationstatistics-old
 78+ $msgs = array( 'ns', 'total', 'stable', 'latest', 'synced', 'old' ); // our headings
 79+ foreach ( $msgs as $msg ) {
 80+ $wgOut->addHTML( '<th>' .
 81+ wfMsgExt( "validationstatistics-$msg", 'parseinline' ) . '</th>' );
 82+ }
 83+ $wgOut->addHTML( "</tr>\n" );
 84+ $namespaces = FlaggedRevs::getReviewNamespaces();
 85+ foreach ( $namespaces as $namespace ) {
 86+ $row = $this->db->selectRow( 'flaggedrevs_stats', '*',
 87+ array( 'namespace' => $namespace ) );
 88+ if( !$row ) continue; // NS added to config recently?
 89+
 90+ $NsText = $wgContLang->getFormattedNsText( $row->namespace );
 91+ $NsText = $NsText ? $NsText : wfMsgHTML( 'blanknamespace' );
 92+
 93+ $percRev = intval( $row->total ) == 0
 94+ ? '-' // devision by zero
 95+ : wfMsg( 'parentheses',
 96+ wfMsgExt( 'percent', array( 'escapenoentities' ),
 97+ $wgLang->formatnum( sprintf( '%4.2f',
 98+ 100 * intval( $row->reviewed ) / intval( $row->total ) ) )
 99+ )
 100+ );
 101+ $percLatest = intval( $row->total ) == 0
 102+ ? '-' // devision by zero
 103+ : wfMsg( 'parentheses',
 104+ wfMsgExt( 'percent', array( 'escapenoentities' ),
 105+ $wgLang->formatnum( sprintf( '%4.2f',
 106+ 100 * intval( $row->synced ) / intval( $row->total ) ) )
 107+ )
 108+ );
 109+ $percSynced = intval( $row->reviewed ) == 0
 110+ ? '-' // devision by zero
 111+ : wfMsgExt( 'percent', array( 'escapenoentities' ),
 112+ $wgLang->formatnum( sprintf( '%4.2f',
 113+ 100 * intval( $row->synced ) / intval( $row->reviewed ) ) )
 114+ );
 115+ $outdated = intval( $row->reviewed ) - intval( $row->synced );
 116+ $outdated = $wgLang->formatnum( max( 0, $outdated ) ); // lag between queries
 117+
 118+ $wgOut->addHTML(
 119+ "<tr align='center'>
 120+ <td>" .
 121+ htmlspecialchars( $NsText ) .
 122+ "</td>
 123+ <td>" .
 124+ htmlspecialchars( $wgLang->formatnum( $row->total ) ) .
 125+ "</td>
 126+ <td>" .
 127+ htmlspecialchars( $wgLang->formatnum( $row->reviewed ) .
 128+ $wgContLang->getDirMark() ) . " <i>$percRev</i>
 129+ </td>
 130+ <td>" .
 131+ htmlspecialchars( $wgLang->formatnum( $row->synced ) .
 132+ $wgContLang->getDirMark() ) . " <i>$percLatest</i>
 133+ </td>
 134+ <td>" .
 135+ $percSynced .
 136+ "</td>
 137+ <td>" .
 138+ $this->skin->linkKnown( SpecialPage::getTitleFor( 'PendingChanges' ),
 139+ htmlspecialchars( $outdated ),
 140+ array(),
 141+ array( 'namespace' => $namespace )
 142+ ) .
 143+ "</td>
 144+ </tr>"
 145+ );
 146+ }
 147+ $wgOut->addHTML( Xml::closeElement( 'table' ) );
 148+ # Is there a top X user list? If so, then show it...
 149+ $data = $this->getTopReviewers();
 150+ if ( is_array( $data ) && count( $data ) ) {
 151+ $wgOut->addWikiMsg( 'validationstatistics-utable',
 152+ $wgLang->formatNum( $wgFlaggedRevsStats['topReviewersCount'] ),
 153+ $wgLang->formatNum( $wgFlaggedRevsStats['topReviewersHours'] )
 154+ );
 155+ $css = 'wikitable flaggedrevs_stats_table';
 156+ $reviewChart = "<table class='$css' style='white-space: nowrap;'>\n";
 157+ $reviewChart .= '<tr><th>' . wfMsgHtml( 'validationstatistics-user' ) .
 158+ '</th><th>' . wfMsgHtml( 'validationstatistics-reviews' ) . '</th></tr>';
 159+ foreach ( $data as $userId => $reviews ) {
 160+ $reviewChart .= '<tr><td>' . htmlspecialchars( User::whois( $userId ) ) .
 161+ '</td><td>' . $wgLang->formatNum( $reviews ) . '</td></tr>';
 162+ }
 163+ $reviewChart .= "</table>\n";
 164+ $wgOut->addHTML( $reviewChart );
 165+ }
 166+ }
 167+
 168+ protected function maybeUpdate() {
 169+ global $wgFlaggedRevsStatsAge;
 170+ if ( !$wgFlaggedRevsStatsAge ) {
 171+ return false;
 172+ }
 173+ $dbCache = wfGetCache( CACHE_DB );
 174+ $key = wfMemcKey( 'flaggedrevs', 'statsUpdated' );
 175+ $keySQL = wfMemcKey( 'flaggedrevs', 'statsUpdating' );
 176+ // If a cache update is needed, do so asynchronously.
 177+ // Don't trigger query while another is running.
 178+ if ( $dbCache->get( $key ) ) {
 179+ wfDebugLog( 'ValidationStatistics', __METHOD__ . " skipping, got data" );
 180+ } elseif ( $dbCache->get( $keySQL ) ) {
 181+ wfDebugLog( 'ValidationStatistics', __METHOD__ . " skipping, in progress" );
 182+ } else {
 183+ global $wgPhpCli;
 184+ $ext = !empty( $wgPhpCli ) ? $wgPhpCli : 'php';
 185+ $path = wfEscapeShellArg( dirname( __FILE__ ) . '/../maintenance/updateStats.php' );
 186+ $wiki = wfEscapeShellArg( wfWikiId() );
 187+ $devNull = wfIsWindows() ? "NUL:" : "/dev/null";
 188+ $commandLine = "$ext $path --wiki=$wiki > $devNull &";
 189+ wfDebugLog( 'ValidationStatistics', __METHOD__ . " executing: $commandLine" );
 190+ wfShellExec( $commandLine );
 191+ return true;
 192+ }
 193+ return false;
 194+ }
 195+
 196+ protected function readyForQuery() {
 197+ if ( !$this->db->tableExists( 'flaggedrevs_stats' ) ) {
 198+ return false;
 199+ } else {
 200+ return ( 0 != $this->db->selectField( 'flaggedrevs_stats', 'COUNT(*)' ) );
 201+ }
 202+ }
 203+
 204+ protected function getEditorCount() {
 205+ return $this->db->selectField( 'user_groups', 'COUNT(*)',
 206+ array( 'ug_group' => 'editor' ),
 207+ __METHOD__ );
 208+ }
 209+
 210+ protected function getReviewerCount() {
 211+ return $this->db->selectField( 'user_groups', 'COUNT(*)',
 212+ array( 'ug_group' => 'reviewer' ),
 213+ __METHOD__ );
 214+ }
 215+
 216+ protected function getMeanReviewWait() {
 217+ if ( !$this->db->tableExists( 'flaggedrevs_stats2' ) ) return '-';
 218+ $val = $this->db->selectField( 'flaggedrevs_stats2', 'ave_review_time' );
 219+ return ( $val == false ? '-' : $val );
 220+ }
 221+
 222+ protected function getMedianReviewWait() {
 223+ if ( !$this->db->tableExists( 'flaggedrevs_stats2' ) ) return '-';
 224+ $val = $this->db->selectField( 'flaggedrevs_stats2', 'med_review_time' );
 225+ return ( $val == false ? '-' : $val );
 226+ }
 227+
 228+ protected function getMeanPendingWait() {
 229+ if ( !$this->db->tableExists( 'flaggedrevs_stats2' ) ) return '-';
 230+ $val = $this->db->selectField( 'flaggedrevs_stats2', 'ave_pending_time' );
 231+ return ( $val == false ? '-' : $val );
 232+ }
 233+
 234+ protected function getLastUpdate() {
 235+ if ( !$this->db->tableExists( 'querycache_info' ) ) return '-';
 236+ $val = $this->db->selectField( 'querycache_info', 'qci_timestamp',
 237+ array( 'qci_type' => 'validationstats' ) );
 238+ return ( $val == false ? '-' : $val );
 239+ }
 240+
 241+ // top X reviewers in the last Y hours
 242+ protected function getTopReviewers() {
 243+ global $wgFlaggedRevsStats;
 244+
 245+ $key = wfMemcKey( 'flaggedrevs', 'reviewTopUsers' );
 246+ $dbCache = wfGetCache( CACHE_DB );
 247+ $data = $dbCache->get( $key );
 248+ if ( is_array( $data ) ) {
 249+ return $data; // cache hit
 250+ }
 251+ $limit = (int)$wgFlaggedRevsStats['topReviewersCount'];
 252+ $seconds = 3600*$wgFlaggedRevsStats['topReviewersHours'];
 253+
 254+ $dbr = wfGetDB( DB_SLAVE );
 255+ $cutoff = $dbr->timestamp( time() - $seconds );
 256+ $res = $dbr->select( 'logging',
 257+ array( 'log_user', 'COUNT(*) AS reviews' ),
 258+ array(
 259+ 'log_type' => 'review', // page reviews
 260+ // manual approvals (filter on log_action)
 261+ 'log_action' => array( 'approve', 'approve2', 'approve-i', 'approve2-i' ),
 262+ 'log_timestamp >= ' . $dbr->addQuotes( $cutoff ) // last hour
 263+ ),
 264+ __METHOD__,
 265+ array( 'GROUP BY' => 'log_user', 'ORDER BY' => 'reviews DESC', 'LIMIT' => $limit )
 266+ );
 267+ $data = array();
 268+ foreach ( $res as $row ) {
 269+ $data[$row->log_user] = $row->reviews;
 270+ }
 271+ // Save/cache users
 272+ $dbCache->set( $key, $data, 3600 );
 273+ return $data;
 274+ }
 275+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/ValidationStatistics_body.php
___________________________________________________________________
Added: svn:eol-style
1276 + native
Index: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/ProblemChanges_body.php
@@ -0,0 +1,406 @@
 2+<?php
 3+
 4+class ProblemChanges extends SpecialPage {
 5+ protected $pager = null;
 6+
 7+ public function __construct() {
 8+ parent::__construct( 'ProblemChanges' );
 9+ $this->includable( true );
 10+ }
 11+
 12+ public function execute( $par ) {
 13+ global $wgRequest, $wgUser;
 14+
 15+ $this->setHeaders();
 16+ $this->skin = $wgUser->getSkin();
 17+ $this->level = $wgRequest->getInt( 'level', - 1 );
 18+ $this->tag = trim( $wgRequest->getVal( 'tagfilter' ) );
 19+ $category = trim( $wgRequest->getVal( 'category' ) );
 20+ $catTitle = Title::newFromText( $category );
 21+ $this->category = is_null( $catTitle ) ? '' : $catTitle->getText();
 22+ $feedType = $wgRequest->getVal( 'feed' );
 23+ if ( $this->including() ) {
 24+ $incLimit = $this->parseParams( $par ); // apply non-URL params
 25+ }
 26+
 27+ $this->pager = new ProblemChangesPager(
 28+ $this, $this->level, $this->category, $this->tag );
 29+
 30+ # Output appropriate format...
 31+ if ( $feedType != null ) {
 32+ $this->feed( $feedType );
 33+ } else {
 34+ if ( $this->including() ) {
 35+ $this->pager->setLimit( $incLimit ); // apply non-URL limit
 36+ } else {
 37+ $this->setSyndicated();
 38+ $this->showForm();
 39+ }
 40+ $this->showPageList();
 41+ }
 42+ }
 43+
 44+ protected function setSyndicated() {
 45+ global $wgOut, $wgRequest;
 46+ $queryParams = array(
 47+ 'level' => $wgRequest->getIntOrNull( 'level' ),
 48+ 'tag' => $wgRequest->getVal( 'tag' ),
 49+ 'category' => $wgRequest->getVal( 'category' ),
 50+ );
 51+ $wgOut->setSyndicated( true );
 52+ $wgOut->setFeedAppendQuery( wfArrayToCGI( $queryParams ) );
 53+ }
 54+
 55+ public function showForm() {
 56+ global $wgOut, $wgScript, $wgLang;
 57+ // Add explanatory text
 58+ $wgOut->addWikiMsg( 'problemchanges-list',
 59+ $wgLang->formatNum( $this->pager->getNumRows() ) );
 60+
 61+ $form = Html::openElement( 'form', array( 'name' => 'problemchanges',
 62+ 'action' => $wgScript, 'method' => 'get' ) ) . "\n";
 63+ $form .= "<fieldset><legend>" . wfMsg( 'problemchanges-legend' ) . "</legend>\n";
 64+ $form .= Html::hidden( 'title', $this->getTitle()->getPrefixedDBKey() ) . "\n";
 65+ $form .=
 66+ ( FlaggedRevs::qualityVersions()
 67+ ? "<span style='white-space: nowrap;'>" .
 68+ FlaggedRevsXML::getLevelMenu( $this->level, 'revreview-filter-stable' ) .
 69+ '</span> '
 70+ : ""
 71+ );
 72+ $tagForm = ChangeTags::buildTagFilterSelector( $this->tag );
 73+ if ( count( $tagForm ) ) {
 74+ $form .= Xml::tags( 'td', array( 'class' => 'mw-label' ), $tagForm[0] );
 75+ $form .= Xml::tags( 'td', array( 'class' => 'mw-input' ), $tagForm[1] );
 76+ }
 77+ $form .= '<br />' .
 78+ Xml::label( wfMsg( "problemchanges-category" ), 'wpCategory' ) . '&#160;' .
 79+ Xml::input( 'category', 30, $this->category, array( 'id' => 'wpCategory' ) ) . ' ';
 80+ $form .= Xml::submitButton( wfMsg( 'allpagessubmit' ) ) . "\n";
 81+ $form .= '</fieldset>';
 82+ $form .= Html::closeElement( 'form' ) . "\n";
 83+
 84+ $wgOut->addHTML( $form );
 85+ }
 86+
 87+ public function showPageList() {
 88+ global $wgOut;
 89+ // Viewing the page normally...
 90+ if ( !$this->including() ) {
 91+ if ( $this->pager->getNumRows() ) {
 92+ $wgOut->addHTML( $this->pager->getNavigationBar() );
 93+ $wgOut->addHTML( $this->pager->getBody() );
 94+ $wgOut->addHTML( $this->pager->getNavigationBar() );
 95+ } else {
 96+ $wgOut->addWikiMsg( 'problemchanges-none' );
 97+ }
 98+ // If this page is transcluded...
 99+ } else {
 100+ if ( $this->pager->getNumRows() ) {
 101+ $wgOut->addHTML( $this->pager->getBody() );
 102+ } else {
 103+ $wgOut->addWikiMsg( 'problemchanges-none' );
 104+ }
 105+ }
 106+ }
 107+
 108+ // set pager parameters from $par, return pager limit
 109+ protected function parseParams( $par ) {
 110+ $bits = preg_split( '/\s*,\s*/', trim( $par ) );
 111+ $limit = false;
 112+ foreach ( $bits as $bit ) {
 113+ if ( is_numeric( $bit ) )
 114+ $limit = intval( $bit );
 115+ $m = array();
 116+ if ( preg_match( '/^limit=(\d+)$/', $bit, $m ) )
 117+ $limit = intval( $m[1] );
 118+ if ( preg_match( '/^category=(.+)$/', $bit, $m ) )
 119+ $this->category = $m[1];
 120+ if ( preg_match( '/^tagfilter=(.+)$/', $bit, $m ) )
 121+ $this->tag = $m[1];
 122+ }
 123+ return $limit;
 124+ }
 125+
 126+ /**
 127+ * Output a subscription feed listing recent edits to this page.
 128+ * @param string $type
 129+ */
 130+ protected function feed( $type ) {
 131+ global $wgFeed, $wgFeedClasses, $wgFeedLimit, $wgOut;
 132+ if ( !$wgFeed ) {
 133+ $wgOut->addWikiMsg( 'feed-unavailable' );
 134+ return;
 135+ }
 136+ if ( !isset( $wgFeedClasses[$type] ) ) {
 137+ $wgOut->addWikiMsg( 'feed-invalid' );
 138+ return;
 139+ }
 140+ $feed = new $wgFeedClasses[$type](
 141+ $this->feedTitle(),
 142+ wfMsg( 'tagline' ),
 143+ $this->getTitle()->getFullUrl()
 144+ );
 145+ $this->pager->mLimit = min( $wgFeedLimit, $this->pager->mLimit );
 146+
 147+ $feed->outHeader();
 148+ if ( $this->pager->getNumRows() > 0 ) {
 149+ foreach ( $this->pager->mResult as $row ) {
 150+ $feed->outItem( $this->feedItem( $row ) );
 151+ }
 152+ }
 153+ $feed->outFooter();
 154+ }
 155+
 156+ protected function feedTitle() {
 157+ global $wgContLanguageCode, $wgSitename;
 158+ $page = SpecialPage::getPage( 'ProblemChanges' );
 159+ $desc = $page->getDescription();
 160+ return "$wgSitename - $desc [$wgContLanguageCode]";
 161+ }
 162+
 163+ protected function feedItem( $row ) {
 164+ $title = Title::MakeTitle( $row->page_namespace, $row->page_title );
 165+ if ( $title ) {
 166+ $date = $row->pending_since;
 167+ $comments = $title->getTalkPage()->getFullURL();
 168+ $curRev = Revision::newFromTitle( $title );
 169+ return new FeedItem(
 170+ $title->getPrefixedText(),
 171+ FeedUtils::formatDiffRow( $title, $row->stable, $curRev->getId(),
 172+ $row->pending_since, $curRev->getComment() ),
 173+ $title->getFullURL(),
 174+ $date,
 175+ $curRev->getUserText(),
 176+ $comments
 177+ );
 178+ } else {
 179+ return null;
 180+ }
 181+ }
 182+
 183+ public function formatRow( $row ) {
 184+ global $wgLang, $wgUser;
 185+ $css = $quality = $tags = $underReview = '';
 186+
 187+ $title = Title::newFromRow( $row );
 188+ $link = $this->skin->link( $title );
 189+ $review = $this->skin->knownLink( $title,
 190+ wfMsg( 'pendingchanges-diff' ),
 191+ array(),
 192+ 'diff=cur&oldid=' . intval($row->stable) . '&diffonly=0' );
 193+ # Show quality level if there are several
 194+ if ( FlaggedRevs::qualityVersions() ) {
 195+ $quality = $row->quality
 196+ ? wfMsgHtml( 'revreview-lev-quality' )
 197+ : wfMsgHtml( 'revreview-lev-basic' );
 198+ $quality = " <b>[{$quality}]</b>";
 199+ }
 200+ # What are the tags?
 201+ $dbTags = self::getRevisionTags( $title->getArticleID(), $row->stable );
 202+ if ( $dbTags ) {
 203+ $tags = htmlspecialchars( implode( ', ', $dbTags ) );
 204+ $tags = ' <b>' . wfMsgHtml( 'parentheses', $tags ) . '</b>';
 205+ }
 206+ # Is anybody watching?
 207+ if ( !$this->including() && $wgUser->isAllowed( 'unreviewedpages' ) ) {
 208+ $uw = FRUserActivity::numUsersWatchingPage( $title );
 209+ $watching = $uw
 210+ ? wfMsgExt( 'pendingchanges-watched', 'parsemag', $wgLang->formatNum( $uw ) )
 211+ : wfMsgHtml( 'pendingchanges-unwatched' );
 212+ $watching = " {$watching}";
 213+ } else {
 214+ $uw = - 1;
 215+ $watching = ''; // leave out data
 216+ }
 217+ # Get how long the first unreviewed edit has been waiting...
 218+ if ( $row->pending_since ) {
 219+ static $currentTime;
 220+ $currentTime = wfTimestamp( TS_UNIX ); // now
 221+ $firstPendingTime = wfTimestamp( TS_UNIX, $row->pending_since );
 222+ $hours = ( $currentTime - $firstPendingTime ) / 3600;
 223+ // After three days, just use days
 224+ if ( $hours > ( 3 * 24 ) ) {
 225+ $days = round( $hours / 24, 0 );
 226+ $age = wfMsgExt( 'pendingchanges-days',
 227+ 'parsemag', $wgLang->formatNum( $days ) );
 228+ // If one or more hours, use hours
 229+ } elseif ( $hours >= 1 ) {
 230+ $hours = round( $hours, 0 );
 231+ $age = wfMsgExt( 'pendingchanges-hours',
 232+ 'parsemag', $wgLang->formatNum( $hours ) );
 233+ } else {
 234+ $age = wfMsg( 'pendingchanges-recent' ); // hot off the press :)
 235+ }
 236+ // Oh-noes!
 237+ $css = self::getLineClass( $hours, $uw );
 238+ $css = $css ? " class='$css'" : "";
 239+ } else {
 240+ $age = ""; // wtf?
 241+ }
 242+ # Show if a user is looking at this page
 243+ list( $u, $ts ) = FRUserActivity::getUserReviewingDiff( $row->stable, $row->page_latest );
 244+ if ( $u !== null ) {
 245+ $underReview = ' <span class="fr-under-review">' .
 246+ wfMsgHtml( 'pendingchanges-viewing' ) . '</span>';
 247+ }
 248+
 249+ return( "<li{$css}>{$link} ({$review}) <i>{$age}</i>" .
 250+ "{$quality}{$tags}{$watching}{$underReview}</li>" );
 251+ }
 252+
 253+ /**
 254+ * Get the tags of the revisions of a page after a certain rev
 255+ * @param integer $pageId, page ID
 256+ * @param integer $revId, rev ID
 257+ */
 258+ protected static function getRevisionTags( $pageId, $revId ) {
 259+ $tags = array();
 260+ $dbr = wfGetDB( DB_SLAVE );
 261+ $res = $dbr->select(
 262+ array( 'revision', 'change_tag' ),
 263+ 'DISTINCT(ct_tag)', // unique tags
 264+ array( 'rev_page' => $pageId, 'rev_id > ' . intval($revId),
 265+ 'rev_id = ct_rev_id' ),
 266+ __METHOD__
 267+ );
 268+ foreach( $res as $row ) {
 269+ $tags[] = $row->ct_tag;
 270+ }
 271+ return $tags;
 272+ }
 273+
 274+ protected static function getLineClass( $hours, $uw ) {
 275+ if ( $uw == 0 )
 276+ return 'fr-unreviewed-unwatched';
 277+ else
 278+ return "";
 279+ }
 280+}
 281+
 282+/**
 283+ * Query to list out outdated reviewed pages
 284+ */
 285+class ProblemChangesPager extends AlphabeticPager {
 286+ public $mForm;
 287+ protected $category, $namespace, $tag;
 288+
 289+ const PAGE_LIMIT = 100; // Don't get too expensive
 290+
 291+ function __construct( $form, $level = - 1, $category = '', $tag = '' )
 292+ {
 293+ $this->mForm = $form;
 294+ # Must be a content page...
 295+ $this->namespace = FlaggedRevs::getReviewNamespaces();
 296+ # Sanity check level: 0 = checked; 1 = quality; 2 = pristine
 297+ $this->level = ( $level >= 0 && $level <= 2 ) ? $level : - 1;
 298+ $this->tag = $tag;
 299+ $this->category = $category ? str_replace( ' ', '_', $category ) : null;
 300+ parent::__construct();
 301+ // Don't get to expensive
 302+ $this->mLimitsShown = array( 20, 50, 100 );
 303+ $this->setLimit( $this->mLimit ); // apply max limit
 304+ }
 305+
 306+ function setLimit( $limit ) {
 307+ $this->mLimit = min( $limit, self::PAGE_LIMIT );
 308+ }
 309+
 310+ function formatRow( $row ) {
 311+ return $this->mForm->formatRow( $row );
 312+ }
 313+
 314+ function getDefaultDirections() {
 315+ return false;
 316+ }
 317+
 318+ function getQueryInfo() {
 319+ global $wgOldChangeTagsIndex;
 320+ $tables = array( 'revision', 'change_tag', 'page' );
 321+ $fields = array( 'page_namespace' , 'page_title', 'page_latest' );
 322+ $ctIndex = $wgOldChangeTagsIndex ?
 323+ 'ct_rev_id' : 'change_tag_rev_tag';
 324+ # Show outdated "stable" pages
 325+ if ( $this->level < 0 ) {
 326+ $fields[] = 'fp_stable AS stable';
 327+ $fields[] = 'fp_quality AS quality';
 328+ $fields[] = 'fp_pending_since AS pending_since';
 329+ # Find revisions that are tagged as such
 330+ $conds[] = 'fp_pending_since IS NOT NULL';
 331+ $conds[] = 'rev_page = fp_page_id';
 332+ $conds[] = 'rev_id > fp_stable';
 333+ $conds[] = 'ct_rev_id = rev_id';
 334+ if ( $this->tag != '' ) {
 335+ $conds['ct_tag'] = $this->tag;
 336+ }
 337+ $conds[] = 'page_id = fp_page_id';
 338+ $useIndex = array(
 339+ 'flaggedpages' => 'fp_pending_since', 'change_tag' => $ctIndex );
 340+ # Filter by category
 341+ if ( $this->category != '' ) {
 342+ array_unshift( $tables, 'categorylinks' ); // order matters
 343+ $conds[] = 'cl_from = fp_page_id';
 344+ $conds['cl_to'] = $this->category;
 345+ $useIndex['categorylinks'] = 'cl_from';
 346+ }
 347+ array_unshift( $tables, 'flaggedpages' ); // order matters
 348+ $this->mIndexField = 'fp_pending_since';
 349+ $groupBy = 'fp_pending_since,fp_page_id';
 350+ # Show outdated pages for a specific review level
 351+ } else {
 352+ $fields[] = 'fpp_rev_id AS stable';
 353+ $fields[] = 'fpp_quality AS quality';
 354+ $fields[] = 'fpp_pending_since AS pending_since';
 355+ $conds[] = 'fpp_pending_since IS NOT NULL';
 356+ $conds[] = 'page_id = fpp_page_id';
 357+ # Find revisions that are tagged as such
 358+ $conds[] = 'rev_page = page_id';
 359+ $conds[] = 'rev_id > fpp_rev_id';
 360+ $conds[] = 'rev_id = ct_rev_id';
 361+ $conds['ct_tag'] = $this->tag;
 362+ $useIndex = array(
 363+ 'flaggedpage_pending' => 'fpp_quality_pending', 'change_tag' => $ctIndex );
 364+ # Filter by review level
 365+ $conds['fpp_quality'] = $this->level;
 366+ # Filter by category
 367+ if ( $this->category ) {
 368+ array_unshift( $tables, 'categorylinks' ); // order matters
 369+ $conds[] = 'cl_from = fpp_page_id';
 370+ $conds['cl_to'] = $this->category;
 371+ $useIndex['categorylinks'] = 'cl_from';
 372+ }
 373+ array_unshift( $tables, 'flaggedpage_pending' ); // order matters
 374+ $this->mIndexField = 'fpp_pending_since';
 375+ $groupBy = 'fpp_pending_since,fpp_page_id';
 376+ }
 377+ $fields[] = $this->mIndexField; // Pager needs this
 378+ $conds['page_namespace'] = $this->namespace; // sanity check NS
 379+ return array(
 380+ 'tables' => $tables,
 381+ 'fields' => $fields,
 382+ 'conds' => $conds,
 383+ 'options' => array( 'USE INDEX' => $useIndex,
 384+ 'GROUP BY' => $groupBy, 'STRAIGHT_JOIN' )
 385+ );
 386+ }
 387+
 388+ function getIndexField() {
 389+ return $this->mIndexField;
 390+ }
 391+
 392+ function getStartBody() {
 393+ wfProfileIn( __METHOD__ );
 394+ # Do a link batch query
 395+ $lb = new LinkBatch();
 396+ foreach ( $this->mResult as $row ) {
 397+ $lb->add( $row->page_namespace, $row->page_title );
 398+ }
 399+ $lb->execute();
 400+ wfProfileOut( __METHOD__ );
 401+ return '<ul>';
 402+ }
 403+
 404+ function getEndBody() {
 405+ return '</ul>';
 406+ }
 407+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/ProblemChanges_body.php
___________________________________________________________________
Added: svn:eol-style
1408 + native
Index: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/ReviewedPages_body.php
@@ -0,0 +1,191 @@
 2+<?php
 3+
 4+class ReviewedPages extends SpecialPage {
 5+ protected $pager = null;
 6+
 7+ public function __construct() {
 8+ parent::__construct( 'ReviewedPages' );
 9+ }
 10+
 11+ public function execute( $par ) {
 12+ global $wgRequest, $wgUser;
 13+
 14+ $this->setHeaders();
 15+ $this->skin = $wgUser->getSkin();
 16+
 17+ # Check if there is a featured level
 18+ $maxType = FlaggedRevs::pristineVersions() ? 2 : 1;
 19+
 20+ $this->namespace = $wgRequest->getInt( 'namespace' );
 21+ $this->type = $wgRequest->getInt( 'level', - 1 );
 22+ $this->type = min( $this->type, $maxType );
 23+ $this->hideRedirs = $wgRequest->getBool( 'hideredirs', true );
 24+
 25+ $this->pager = new ReviewedPagesPager(
 26+ $this, array(), $this->type, $this->namespace, $this->hideRedirs );
 27+
 28+ $this->showForm();
 29+ $this->showPageList();
 30+ }
 31+
 32+ public function showForm() {
 33+ global $wgOut, $wgScript, $wgLang;
 34+
 35+ // Text to explain level select (if there are several levels)
 36+ if ( FlaggedRevs::qualityVersions() ) {
 37+ $wgOut->addWikiMsg( 'reviewedpages-list',
 38+ $wgLang->formatNum( $this->pager->getNumRows() ) );
 39+ }
 40+ $form = Html::openElement( 'form',
 41+ array( 'name' => 'reviewedpages', 'action' => $wgScript, 'method' => 'get' ) );
 42+ $form .= "<fieldset><legend>" . wfMsgHtml( 'reviewedpages-leg' ) . "</legend>\n";
 43+
 44+ // show/hide links
 45+ $showhide = array( wfMsgHtml( 'show' ), wfMsgHtml( 'hide' ) );
 46+ $onoff = 1 - $this->hideRedirs;
 47+ $link = $this->skin->link( $this->getTitle(), $showhide[$onoff], array(),
 48+ array( 'hideredirs' => $onoff, 'namespace' => $this->namespace )
 49+ );
 50+ $showhideredirs = wfMsgHtml( 'whatlinkshere-hideredirs', $link );
 51+
 52+ $fields = array();
 53+ $namespaces = FlaggedRevs::getReviewNamespaces();
 54+ if ( count( $namespaces ) > 1 ) {
 55+ $fields[] = FlaggedRevsXML::getNamespaceMenu( $this->namespace ) . ' ';
 56+ }
 57+ if ( FlaggedRevs::qualityVersions() ) {
 58+ $fields[] = FlaggedRevsXML::getLevelMenu( $this->type ) . ' ';
 59+ }
 60+ $form .= implode( ' ', $fields ) . ' ';
 61+ $form .= $showhideredirs;
 62+
 63+ if ( count( $fields ) ) {
 64+ $form .= " " . Xml::submitButton( wfMsg( 'go' ) );
 65+ }
 66+ $form .= Html::hidden( 'title', $this->getTitle()->getPrefixedDBKey() ) . "\n";
 67+ $form .= "</fieldset>";
 68+ $form .= Html::closeElement( 'form ' ) . "\n";
 69+
 70+ $wgOut->addHTML( $form );
 71+ }
 72+
 73+ protected function showPageList() {
 74+ global $wgOut;
 75+ $num = $this->pager->getNumRows();
 76+ if ( $num ) {
 77+ $wgOut->addHTML( $this->pager->getNavigationBar() );
 78+ $wgOut->addHTML( $this->pager->getBody() );
 79+ $wgOut->addHTML( $this->pager->getNavigationBar() );
 80+ } else {
 81+ $wgOut->addHTML( wfMsgExt( 'reviewedpages-none', array( 'parse' ) ) );
 82+ }
 83+ }
 84+
 85+ public function formatRow( $row ) {
 86+ global $wgLang;
 87+ $title = Title::newFromRow( $row );
 88+ # Link to page
 89+ $link = $this->skin->link( $title );
 90+ # Size (bytes)
 91+ $stxt = '';
 92+ if ( !is_null( $size = $row->page_len ) ) {
 93+ if ( $size == 0 ) {
 94+ $stxt = ' <small>' . wfMsgHtml( 'historyempty' ) . '</small>';
 95+ } else {
 96+ $stxt = ' <small>' .
 97+ wfMsgExt( 'historysize', 'parsemag', $wgLang->formatNum( $size ) ) .
 98+ '</small>';
 99+ }
 100+ }
 101+ # Link to list of reviewed versions for page
 102+ $list = $this->skin->linkKnown(
 103+ SpecialPage::getTitleFor( 'ReviewedVersions' ),
 104+ wfMsgHtml( 'reviewedpages-all' ),
 105+ array(),
 106+ 'page=' . $title->getPrefixedUrl()
 107+ );
 108+ # Link to highest tier rev
 109+ $best = '';
 110+ if ( FlaggedRevs::qualityVersions() ) {
 111+ $best = $this->skin->linkKnown(
 112+ $title,
 113+ wfMsgHtml( 'reviewedpages-best' ),
 114+ array(),
 115+ 'stableid=best'
 116+ );
 117+ $best = " [$best]";
 118+ }
 119+
 120+ return "<li>$link $stxt ($list)$best</li>";
 121+ }
 122+}
 123+
 124+/**
 125+ * Query to list out reviewed pages
 126+ */
 127+class ReviewedPagesPager extends AlphabeticPager {
 128+ public $mForm, $mConds, $namespace, $type;
 129+
 130+ function __construct( $form, $conds = array(), $type = 0, $namespace = 0, $hideRedirs = 1 ) {
 131+ $this->mForm = $form;
 132+ $this->mConds = $conds;
 133+ $this->type = $type;
 134+ # Must be a content page...
 135+ if ( !is_null( $namespace ) ) {
 136+ $namespace = intval( $namespace );
 137+ }
 138+ $vnamespaces = FlaggedRevs::getReviewNamespaces();
 139+ if ( is_null( $namespace ) || !in_array( $namespace, $vnamespaces ) ) {
 140+ $namespace = !$vnamespaces ? - 1 : $vnamespaces[0];
 141+ }
 142+ $this->namespace = $namespace;
 143+ $this->hideRedirs = $hideRedirs;
 144+
 145+ parent::__construct();
 146+ }
 147+
 148+ function formatRow( $row ) {
 149+ return $this->mForm->formatRow( $row );
 150+ }
 151+
 152+ function getQueryInfo() {
 153+ $conds = $this->mConds;
 154+ $conds[] = 'page_id = fp_page_id';
 155+ $index = 'PRIMARY';
 156+ if ( $this->type >= 0 ) {
 157+ $conds['fp_quality'] = $this->type;
 158+ $index = 'fp_quality_page';
 159+ }
 160+ if ( $this->hideRedirs ) {
 161+ $conds['page_is_redirect'] = 0;
 162+ }
 163+ $conds['page_namespace'] = $this->namespace; // Sanity check NS
 164+ return array(
 165+ 'tables' => array( 'flaggedpages', 'page' ),
 166+ 'fields' => 'page_namespace,page_title,page_len,fp_page_id',
 167+ 'conds' => $conds,
 168+ 'options' => array( 'USE INDEX' => array( 'flaggedpages' => $index,
 169+ 'page' => 'PRIMARY' ) )
 170+ );
 171+ }
 172+
 173+ function getIndexField() {
 174+ return 'fp_page_id';
 175+ }
 176+
 177+ function getStartBody() {
 178+ wfProfileIn( __METHOD__ );
 179+ # Do a link batch query
 180+ $lb = new LinkBatch();
 181+ foreach ( $this->mResult as $row ) {
 182+ $lb->add( $row->page_namespace, $row->page_title );
 183+ }
 184+ $lb->execute();
 185+ wfProfileOut( __METHOD__ );
 186+ return '<ul>';
 187+ }
 188+
 189+ function getEndBody() {
 190+ return '</ul>';
 191+ }
 192+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/ReviewedPages_body.php
___________________________________________________________________
Added: svn:eol-style
1193 + native
Index: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/StablePages_body.php
@@ -0,0 +1,187 @@
 2+<?php
 3+
 4+// Assumes $wgFlaggedRevsProtection is on
 5+class StablePages extends SpecialPage {
 6+ protected $pager = null;
 7+
 8+ public function __construct() {
 9+ parent::__construct( 'StablePages' );
 10+ }
 11+
 12+ public function execute( $par ) {
 13+ global $wgRequest, $wgUser;
 14+
 15+ $this->setHeaders();
 16+ $this->skin = $wgUser->getSkin();
 17+
 18+ $this->namespace = $wgRequest->getIntOrNull( 'namespace' );
 19+ $this->autoreview = $wgRequest->getVal( 'restriction', '' );
 20+ $this->indef = $wgRequest->getBool( 'indef', false );
 21+
 22+ $this->pager = new StablePagesPager( $this, array(),
 23+ $this->namespace, $this->autoreview, $this->indef );
 24+
 25+ $this->showForm();
 26+ $this->showPageList();
 27+ }
 28+
 29+ protected function showForm() {
 30+ global $wgOut, $wgScript, $wgLang;
 31+ $wgOut->addWikiMsg( 'stablepages-list',
 32+ $wgLang->formatNum( $this->pager->getNumRows() ) );
 33+ $fields = array();
 34+ # Namespace selector
 35+ if ( count( FlaggedRevs::getReviewNamespaces() ) > 1 ) {
 36+ $fields[] = FlaggedRevsXML::getNamespaceMenu( $this->namespace, '' );
 37+ }
 38+ # Restriction level selector
 39+ if ( FlaggedRevs::getRestrictionLevels() ) {
 40+ $fields[] = FlaggedRevsXML::getRestrictionFilterMenu( $this->autoreview );
 41+ }
 42+ $fields[] = Xml::checkLabel( wfMsg( 'stablepages-indef' ), 'indef',
 43+ 'stablepages-indef', $this->indef );
 44+
 45+ $form = Html::openElement( 'form',
 46+ array( 'name' => 'stablepages', 'action' => $wgScript, 'method' => 'get' ) );
 47+ $form .= Html::hidden( 'title', $this->getTitle()->getPrefixedDBKey() );
 48+ $form .= "<fieldset><legend>" . wfMsg( 'stablepages' ) . "</legend>\n";
 49+ $form .= implode( '&#160;', $fields ) . '&nbsp';
 50+ $form .= " " . Xml::submitButton( wfMsg( 'go' ) );
 51+ $form .= "</fieldset>\n";
 52+ $form .= Html::closeElement( 'form' ) . "\n";
 53+
 54+ $wgOut->addHTML( $form );
 55+ }
 56+
 57+ protected function showPageList() {
 58+ global $wgOut;
 59+ if ( $this->pager->getNumRows() ) {
 60+ $wgOut->addHTML( $this->pager->getNavigationBar() );
 61+ $wgOut->addHTML( $this->pager->getBody() );
 62+ $wgOut->addHTML( $this->pager->getNavigationBar() );
 63+ } else {
 64+ $wgOut->addWikiMsg( 'stablepages-none' );
 65+ }
 66+ # Purge expired entries on one in every 10 queries
 67+ if ( !mt_rand( 0, 10 ) ) {
 68+ FlaggedPageConfig::purgeExpiredConfigurations();
 69+ }
 70+ }
 71+
 72+ public function formatRow( $row ) {
 73+ global $wgLang;
 74+ $title = Title::makeTitle( $row->page_namespace, $row->page_title );
 75+ # Link to page
 76+ $link = $this->skin->link( $title );
 77+ # Helpful utility links
 78+ $utilLinks = array();
 79+ $utilLinks[] = $this->skin->link( $title,
 80+ wfMsgHtml( 'stablepages-config' ),
 81+ array(), array( 'action' => 'protect' ), 'known' );
 82+ $utilLinks[] = $this->skin->link( $title,
 83+ wfMsgHtml( 'history' ),
 84+ array(), array( 'action' => 'history' ), 'known' );
 85+ $utilLinks[] = $this->skin->link( SpecialPage::getTitleFor( 'Log', 'stable' ),
 86+ wfMsgHtml( 'stable-logpage' ),
 87+ array(), array( 'page' => $title->getPrefixedText() ), 'known' );
 88+ # Autoreview/review restriction level
 89+ $restr = '';
 90+ if ( $row->fpc_level != '' ) {
 91+ $restr = 'autoreview=' . htmlspecialchars( $row->fpc_level );
 92+ $restr = "[$restr]";
 93+ }
 94+ # When these configuration settings expire
 95+ if ( $row->fpc_expiry != 'infinity' && strlen( $row->fpc_expiry ) ) {
 96+ $expiry_description = " (" . wfMsgForContent(
 97+ 'protect-expiring',
 98+ $wgLang->timeanddate( $row->fpc_expiry ),
 99+ $wgLang->date( $row->fpc_expiry ),
 100+ $wgLang->time( $row->fpc_expiry )
 101+ ) . ")";
 102+ } else {
 103+ $expiry_description = "";
 104+ }
 105+ $utilLinks = $wgLang->pipeList( $utilLinks );
 106+ return "<li>{$link} ({$utilLinks}) {$restr}<i>{$expiry_description}</i></li>";
 107+ }
 108+}
 109+
 110+/**
 111+ * Query to list out stable versions for a page
 112+ */
 113+class StablePagesPager extends AlphabeticPager {
 114+ public $mForm, $mConds, $namespace, $override;
 115+
 116+ // @param int $namespace (null for "all")
 117+ // @param string $autoreview ('' for "all", 'none' for no restriction)
 118+ function __construct( $form, $conds = array(), $namespace, $autoreview, $indef ) {
 119+ $this->mForm = $form;
 120+ $this->mConds = $conds;
 121+ $this->indef = $indef;
 122+ # Must be content pages...
 123+ $validNS = FlaggedRevs::getReviewNamespaces();
 124+ if ( is_integer( $namespace ) ) {
 125+ if ( !in_array( $namespace, $validNS ) ) {
 126+ $namespace = $validNS; // fallback to "all"
 127+ }
 128+ } else {
 129+ $namespace = $validNS; // "all"
 130+ }
 131+ $this->namespace = $namespace;
 132+ if ( $autoreview === 'none' ) {
 133+ $autoreview = ''; // 'none' => ''
 134+ } elseif ( $autoreview === '' ) {
 135+ $autoreview = null; // '' => null
 136+ }
 137+ $this->autoreview = $autoreview;
 138+ parent::__construct();
 139+ }
 140+
 141+ function formatRow( $row ) {
 142+ return $this->mForm->formatRow( $row );
 143+ }
 144+
 145+ function getQueryInfo() {
 146+ $conds = $this->mConds;
 147+ $conds[] = 'page_id = fpc_page_id';
 148+ $conds['fpc_override'] = 1;
 149+ if( $this->autoreview !== null ) {
 150+ $conds['fpc_level'] = $this->autoreview;
 151+ }
 152+ $conds['page_namespace'] = $this->namespace;
 153+ # Be sure not to include expired items
 154+ if( $this->indef ) {
 155+ $conds['fpc_expiry'] = Block::infinity();
 156+ } else {
 157+ $encCutoff = $this->mDb->addQuotes( $this->mDb->timestamp() );
 158+ $conds[] = "fpc_expiry > {$encCutoff}";
 159+ }
 160+ return array(
 161+ 'tables' => array( 'flaggedpage_config', 'page' ),
 162+ 'fields' => array( 'page_namespace', 'page_title', 'fpc_override',
 163+ 'fpc_expiry', 'fpc_page_id', 'fpc_level' ),
 164+ 'conds' => $conds,
 165+ 'options' => array()
 166+ );
 167+ }
 168+
 169+ function getIndexField() {
 170+ return 'fpc_page_id';
 171+ }
 172+
 173+ function getStartBody() {
 174+ wfProfileIn( __METHOD__ );
 175+ # Do a link batch query
 176+ $lb = new LinkBatch();
 177+ foreach ( $this->mResult as $row ) {
 178+ $lb->add( $row->page_namespace, $row->page_title );
 179+ }
 180+ $lb->execute();
 181+ wfProfileOut( __METHOD__ );
 182+ return '<ul>';
 183+ }
 184+
 185+ function getEndBody() {
 186+ return '</ul>';
 187+ }
 188+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/StablePages_body.php
___________________________________________________________________
Added: svn:eol-style
1189 + native
Index: trunk/extensions/FlaggedRevs/presentation/modules/flaggedrevs.css
@@ -0,0 +1,368 @@
 2+/**
 3+ * FlaggedRevs Stylesheet
 4+ * @author Aaron Schulz
 5+ */
 6+
 7+/* Standard User Interface */
 8+div.flaggedrevs_basic,
 9+div.flaggedrevs_quality,
 10+div.flaggedrevs_pristine,
 11+div.flaggedrevs_notice {
 12+ border: 1px solid #aaa;
 13+ padding: 5px;
 14+ font-weight: normal;
 15+ line-height: 1.5em;
 16+ margin: .5em 1em 0em 0em;
 17+ text-align: center;
 18+ clear: both;
 19+}
 20+div.flaggedrevs_short_basic img {
 21+ vertical-align: text-bottom;
 22+}
 23+div.flaggedrevs_basic {
 24+ background-color: #f0f8ff;
 25+}
 26+div.flaggedrevs_quality {
 27+ background-color: #f0fff0;
 28+}
 29+div.flaggedrevs_pristine {
 30+ background-color: #fffff0;
 31+}
 32+div.flaggedrevs_notice {
 33+ background-color: #f9f9f9;
 34+}
 35+
 36+table.flaggedrevs_editnotice,
 37+table.flaggedrevs_viewnotice {
 38+ padding: 3px;
 39+ border: 2px solid #6cc8f3;
 40+ background-color: #f9f9f9;
 41+ text-align: left;
 42+ width: 100%;
 43+ clear: both;
 44+}
 45+
 46+div.flaggedrevs_diffnotice,
 47+div.flaggedrevs_preview {
 48+ border: 1px solid #a7d7f9;
 49+ padding: 5px;
 50+ text-align: center;
 51+ clear: both;
 52+}
 53+div.flaggedrevs_diffnotice {
 54+ font-size: 85%;
 55+ background-color: #f9f9f9;
 56+}
 57+div.flaggedrevs_preview {
 58+ background-color: #eaf2fd;
 59+ color: black;
 60+}
 61+
 62+span.flaggedrevs_important {
 63+ font-size: 115%;
 64+ font-weight: bold;
 65+}
 66+
 67+div.flaggedrevs_notes {
 68+ border: 1px solid #aaa;
 69+ background-color: #f9f9f9;
 70+ padding: 5px;
 71+ font-size: 85%;
 72+ margin-left: 50px;
 73+ margin-right: 50px;
 74+ text-align: center;
 75+}
 76+
 77+.fr-text-value {
 78+ width: 100px;
 79+}
 80+
 81+.fr-marker-20,
 82+.fr-marker-40,
 83+.fr-marker-60,
 84+.fr-marker-80,
 85+.fr-marker-100 {
 86+ background-position: bottom left;
 87+ background-repeat: no-repeat;
 88+ padding-bottom: 3px;
 89+}
 90+
 91+.fr-marker-20 {
 92+ /* @embed */
 93+ background-image: url('img/bar_20.png');
 94+}
 95+.fr-marker-40 {
 96+ /* @embed */
 97+ background-image: url('img/bar_40.png');
 98+}
 99+.fr-marker-60 {
 100+ /* @embed */
 101+ background-image: url('img/bar_60.png');
 102+}
 103+.fr-marker-80 {
 104+ /* @embed */
 105+ background-image: url('img/bar_80.png');
 106+}
 107+.fr-marker-100 {
 108+ /* @embed */
 109+ background-image: url('img/bar_100.png');
 110+}
 111+
 112+/* Short User Interface */
 113+div.flaggedrevs_short {
 114+ border: 1px solid #ccc;
 115+ background-color: #ffffff;
 116+ font-size: 95%;
 117+ font-weight: normal;
 118+ margin: 0 0 0 1em;
 119+ line-height: 16px;
 120+ padding: 2px;
 121+ float: right;
 122+}
 123+
 124+/* @noflip */
 125+.rtl div.flaggedrevs_short {
 126+ float: left;
 127+ margin: 0 1em 0 0;
 128+}
 129+
 130+div.flaggedrevs_short_basic {
 131+ white-space: nowrap;
 132+}
 133+
 134+div.flaggedrevs_short_details {
 135+ border: 1px solid #aaa;
 136+ background-color: #ffffff;
 137+ padding: 5px;
 138+ position: absolute;
 139+ top: 0;
 140+ right: -2px;
 141+ width: 25em;
 142+}
 143+
 144+/* @noflip */
 145+.rtl div.flaggedrevs_short_details {
 146+ right: auto;
 147+ left: -2px;
 148+}
 149+
 150+.fr-text {
 151+ height: 1em;
 152+ line-height: 1em;
 153+ margin: 0px 7px 0px 0px;
 154+ padding: 0px;
 155+ font-weight: bold;
 156+ width: 80px;
 157+}
 158+
 159+.fr-value20,
 160+.fr-value40,
 161+.fr-value60,
 162+.fr-value80,
 163+.fr-value100 {
 164+ height: 1em;
 165+ line-height: 1em;
 166+ width: 95px;
 167+ float: left;
 168+ background-repeat: no-repeat;
 169+ background-position: 50% 50%;
 170+ text-align: center;
 171+}
 172+
 173+.fr-value20 {
 174+ /* @embed */
 175+ background-image: url('img/fr-marker-20.png');
 176+}
 177+.fr-value40 {
 178+ /* @embed */
 179+ background-image: url('img/fr-marker-40.png');
 180+}
 181+.fr-value60 {
 182+ /* @embed */
 183+ background-image: url('img/fr-marker-60.png');
 184+}
 185+.fr-value80 {
 186+ /* @embed */
 187+ background-image: url('img/fr-marker-80.png');
 188+}
 189+.fr-value100 {
 190+ /* @embed */
 191+ background-image: url('img/fr-marker-100.png');
 192+}
 193+
 194+/* Both User Interfaces */
 195+.flaggedrevs-color-0 {
 196+ background-color: #f9f9f9;
 197+}
 198+.flaggedrevs-color-1 {
 199+ background-color: #f0f8ff;
 200+}
 201+.flaggedrevs-color-2 {
 202+ background-color: #f0fff0;
 203+}
 204+.flaggedrevs-color-3 {
 205+ background-color: #fffff0;
 206+}
 207+
 208+.flaggedrevs-pending {
 209+ background-color: #ffeeaa;
 210+}
 211+.flaggedrevs-unreviewed {
 212+ background-color: #faebd7;
 213+}
 214+
 215+a.fr-toggle-symbol {
 216+ color: blue;
 217+ white-space: nowrap;
 218+ font-family: monospace;
 219+ font-weight: bold;
 220+ cursor: pointer;
 221+ margin: 0 .3em 0 .3em;
 222+}
 223+
 224+a.fr-toggle-text {
 225+ color: blue;
 226+ font-weight: bold;
 227+ cursor: pointer;
 228+}
 229+
 230+img.fr-toggle-arrow {
 231+ cursor: pointer;
 232+}
 233+
 234+li.fr-hist-stable-margin {
 235+ margin-top: 2em;
 236+}
 237+
 238+img.flaggedrevs-icon {
 239+ margin-right: .2em;
 240+ margin-left: .2em;
 241+}
 242+
 243+.fr-diff-ratings {
 244+ font-size: 90%;
 245+ font-weight: bold;
 246+ line-height: 1em;
 247+ width: 100%;
 248+}
 249+
 250+.fr-diff-to-stable {
 251+ line-height: 1em;
 252+}
 253+
 254+.fr-hist-basic-user,
 255+.fr-hist-quality-user,
 256+.fr-hist-basic-auto,
 257+.fr-hist-quality-auto {
 258+ font-weight: bold;
 259+}
 260+
 261+/* RC pending changes notice */
 262+.fr-watchlist-pending-notice {
 263+ padding: 3px;
 264+ margin: 5px;
 265+ border: 1px solid #990000;
 266+ background-color: #FEECD7;
 267+}
 268+
 269+/* Special pages */
 270+.fr-pending-long {
 271+ background-color: #f5ecec;
 272+}
 273+.fr-pending-long2 {
 274+ background-color: #f5dddd;
 275+}
 276+.fr-pending-long3 {
 277+ background-color: #e2caca;
 278+}
 279+
 280+.fr-unreviewed-unwatched {
 281+ background-color: #faebd7;
 282+}
 283+
 284+span.fr-under-review {
 285+ background-color: yellow;
 286+ font-weight: bold;
 287+}
 288+
 289+.mw-fr-reviewlink {
 290+ font-weight: bold;
 291+}
 292+
 293+/* Review form */
 294+.flaggedrevs_reviewform {
 295+ background-color: #f9f9f9;
 296+ font-size: 90%;
 297+ clear: both;
 298+}
 299+
 300+.fr-rating-controls,
 301+.fr-rating-controls-disabled {
 302+ vertical-align: middle;
 303+}
 304+
 305+.fr-rating-controls-disabled {
 306+ color: GrayText;
 307+}
 308+
 309+.fr-rating-options {
 310+ margin-right: 1.5em;
 311+}
 312+
 313+.fr-rating-option-0 {
 314+ background-color: #f5ecec;
 315+}
 316+.fr-rating-option-1 {
 317+ background-color: #f0f8ff;
 318+}
 319+.fr-rating-option-2 {
 320+ background-color: #f0fff0;
 321+}
 322+.fr-rating-option-3 {
 323+ background-color: #fef0db;
 324+}
 325+.fr-rating-option-4 {
 326+ background-color: #fffff0;
 327+}
 328+
 329+.fr-diff-patrollink {
 330+ text-align: center;
 331+}
 332+
 333+.fr-notes-box {
 334+ width: 95%;
 335+ margin: 0em 1em 0em .5em;
 336+}
 337+
 338+.fr-comment-box {
 339+ margin-top: .25em;
 340+}
 341+
 342+.fr-rating-dave {
 343+ background-color: #E0ECF8;
 344+}
 345+
 346+.fr-rating-rave {
 347+ background-color: #E0F8EC;
 348+}
 349+
 350+.fr-hiddenform {
 351+ display: none;
 352+}
 353+
 354+.loading { display: block;
 355+ color: #666666; padding-left: 40px;
 356+ height: 32px;
 357+}
 358+.spinner {
 359+ background-position: left center;
 360+ margin-left: 1em;
 361+ margin-top: -1.3em;
 362+ float: left;
 363+}
 364+
 365+div.langlinks {
 366+ margin-top: 1em;
 367+ padding: 5px;
 368+ border: 1px solid #aaa;
 369+}
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/flaggedrevs.css
___________________________________________________________________
Added: svn:eol-style
1370 + native
Index: trunk/extensions/FlaggedRevs/presentation/modules/flaggedrevs.js
@@ -0,0 +1,274 @@
 2+/**
 3+ * FlaggedRevs Stylesheet
 4+ * @author Aaron Schulz
 5+ * @author Krinkle <krinklemail@gmail.com> 2011
 6+ */
 7+
 8+window.FlaggedRevs = {
 9+ /* Dropdown collapse timer */
 10+ 'boxCollapseTimer': null,
 11+
 12+ /* Enables rating/diff clutter via show/hide */
 13+ 'enableShowhide': function() {
 14+ // Rating detail box
 15+ var toggle = document.getElementById('mw-fr-revisiontoggle');
 16+ if ( toggle ) {
 17+ toggle.style.display = 'inline'; /* show toggle control */
 18+ this.hideBoxDetails(); /* hide the initially displayed ratings */
 19+ }
 20+ // Diff detail box
 21+ toggle = document.getElementById('mw-fr-difftoggle');
 22+ if ( toggle ) {
 23+ toggle.style.display = 'inline'; /* show toggle control */
 24+ var diff = document.getElementById('mw-fr-stablediff');
 25+ if ( diff ) {
 26+ diff.style.display = 'none';
 27+ }
 28+ }
 29+ // Log detail box
 30+ toggle = document.getElementById('mw-fr-logtoggle');
 31+ if ( toggle ) {
 32+ toggle.style.display = 'inline'; /* show toggle control */
 33+ var log = document.getElementById('mw-fr-logexcerpt');
 34+ if ( log ) {
 35+ log.style.display = 'none';
 36+ }
 37+ }
 38+ },
 39+
 40+ /* Expands flag info box details */
 41+ 'showBoxDetails': function() {
 42+ var ratings = document.getElementById('mw-fr-revisiondetails');
 43+ if ( ratings ) {
 44+ ratings.style.display = 'block';
 45+ }
 46+ },
 47+
 48+ /* Collapses flag info box details */
 49+ 'hideBoxDetails': function( event ) {
 50+ var ratings = document.getElementById('mw-fr-revisiondetails');
 51+ if ( ratings ) {
 52+ ratings.style.display = 'none';
 53+ }
 54+ },
 55+
 56+ /* Toggles flag info box details for (+/-) control */
 57+ 'toggleBoxDetails': function() {
 58+ var toggle = document.getElementById('mw-fr-revisiontoggle');
 59+ if ( !toggle ) {
 60+ return;
 61+ }
 62+ var ratings = document.getElementById('mw-fr-revisiondetails');
 63+ if ( !ratings ) {
 64+ return;
 65+ }
 66+ // Collapsed -> expand
 67+ if ( ratings.style.display == 'none' ) {
 68+ this.showBoxDetails();
 69+ toggle.innerHTML = mw.msg('revreview-toggle-hide');
 70+ // Expanded -> collapse
 71+ } else {
 72+ this.hideBoxDetails();
 73+ toggle.innerHTML = mw.msg('revreview-toggle-show');
 74+ }
 75+ },
 76+
 77+ /* Expands flag info box details on mouseOver */
 78+ 'onBoxMouseOver': function( event ) {
 79+ window.clearTimeout( this.boxCollapseTimer );
 80+ this.boxCollapseTimer = null;
 81+ this.showBoxDetails();
 82+ },
 83+
 84+ /* Hides flag info box details on mouseOut *except* for event bubbling */
 85+ 'onBoxMouseOut': function( event ) {
 86+ if ( !this.isMouseOutBubble( event, 'mw-fr-revisiontag' ) ) {
 87+ this.boxCollapseTimer = window.setTimeout( this.hideBoxDetails, 150 );
 88+ }
 89+ },
 90+
 91+ /* Checks is mouseOut event is for a child of parentId */
 92+ 'isMouseOutBubble': function( event, parentId ) {
 93+ var toNode = null;
 94+ if ( event.relatedTarget !== undefined ) {
 95+ toNode = event.relatedTarget; // FF/Opera/Safari
 96+ } else {
 97+ toNode = event.toElement; // IE
 98+ }
 99+ if ( toNode ) {
 100+ var nextParent = toNode.parentNode;
 101+ while ( nextParent ) {
 102+ if ( nextParent.id == parentId ) {
 103+ return true; // event bubbling
 104+ }
 105+ nextParent = nextParent.parentNode; // next up
 106+ }
 107+ }
 108+ return false;
 109+ },
 110+
 111+ /* Toggles diffs */
 112+ 'toggleDiff': function() {
 113+ var diff = document.getElementById('mw-fr-stablediff');
 114+ if ( !diff ) {
 115+ return;
 116+ }
 117+ var toggle = document.getElementById('mw-fr-difftoggle');
 118+ if ( !toggle ) {
 119+ return;
 120+ }
 121+ if ( diff.style.display == 'none' ) {
 122+ diff.style.display = 'block';
 123+ toggle.getElementsByTagName('a')[0].innerHTML =
 124+ mw.msg('revreview-diff-toggle-hide');
 125+ } else {
 126+ diff.style.display = 'none';
 127+ toggle.getElementsByTagName('a')[0].innerHTML =
 128+ mw.msg('revreview-diff-toggle-show');
 129+ }
 130+ },
 131+
 132+ /* Toggles log excerpts */
 133+ 'toggleLog': function() {
 134+ var log = document.getElementById('mw-fr-logexcerpt');
 135+ if ( !log ) {
 136+ return;
 137+ }
 138+ var toggle = document.getElementById('mw-fr-logtoggle');
 139+ if ( !toggle ) {
 140+ return;
 141+ }
 142+ if ( log.style.display == 'none' ) {
 143+ log.style.display = 'block';
 144+ toggle.getElementsByTagName('a')[0].innerHTML =
 145+ mw.msg('revreview-log-toggle-hide');
 146+ } else {
 147+ log.style.display = 'none';
 148+ toggle.getElementsByTagName('a')[0].innerHTML =
 149+ mw.msg('revreview-log-toggle-show');
 150+ }
 151+ },
 152+
 153+ /* Toggles log excerpts */
 154+ 'toggleLogDetails': function() {
 155+ var log = document.getElementById('mw-fr-logexcerpt');
 156+ if ( !log ) {
 157+ return;
 158+ }
 159+ var toggle = document.getElementById('mw-fr-logtoggle');
 160+ if ( !toggle ) {
 161+ return;
 162+ }
 163+ if ( log.style.display == 'none' ) {
 164+ log.style.display = 'block';
 165+ toggle.getElementsByTagName('a')[0].innerHTML = mw.msg('revreview-log-details-hide');
 166+ } else {
 167+ log.style.display = 'none';
 168+ toggle.getElementsByTagName('a')[0].innerHTML = mw.msg('revreview-log-details-show');
 169+ }
 170+ },
 171+
 172+ /* Enables changing of save button when "review this" checkbox changes */
 173+ 'setCheckTrigger': function() {
 174+ var checkbox = document.getElementById('wpReviewEdit');
 175+ if ( checkbox ) {
 176+ checkbox.onclick = FlaggedRevs.updateSaveButton;
 177+ }
 178+ },
 179+
 180+ /* Update save button when "review this" checkbox changes */
 181+ 'updateSaveButton': function() {
 182+ var checkbox = document.getElementById('wpReviewEdit');
 183+ var save = document.getElementById('wpSave');
 184+ if ( checkbox && save ) {
 185+ // Review pending changes
 186+ if ( checkbox.checked ) {
 187+ save.value = mw.msg('savearticle');
 188+ save.title = mw.msg('tooltip-save') +
 189+ ' [' + mw.msg('accesskey-save') + ']';
 190+ // Submit for review
 191+ } else {
 192+ save.value = mw.msg('revreview-submitedit');
 193+ save.title = mw.msg('revreview-submitedit-title')
 194+ + ' [' + mw.msg('accesskey-save') + ']';
 195+ }
 196+ }
 197+ mw.util.updateTooltipAccessKeys( [ save ] ); // update accesskey in save.title
 198+ }
 199+};
 200+
 201+
 202+// Get the revisioncontents div and replace it with actual parsed article contents via an API call
 203+FlaggedRevs.getRevisionContents = function() {
 204+ var revContent = mw.config.get( 'wgRevContents' );
 205+ var $frRevContents = $( '#mw-fr-revisioncontents' );
 206+ var $prevLink = $( '#differences-prevlink' );
 207+ var $nextLink = $( '#differences-nextlink' );
 208+
 209+ if ( $frRevContents.size() ) {
 210+ var diffUIParams = document.getElementById( 'mw-fr-diff-dataform' );
 211+ var oldRevId = diffUIParams.getElementsByTagName( 'input' )[1].value;
 212+ var origContents = $frRevContents.html();
 213+ $frRevContents.html( '<span class="loading mw-small-spinner spinner"></span>'
 214+ + '<span class="loading">' + mw.html.escape( revContent.waiting ) + '</span>' );
 215+ var queryParams = {
 216+ format: 'json',
 217+ action: 'parse',
 218+ prop: 'text|categorieshtml|languageshtml|headitems'
 219+ };
 220+ if ( mw.config.get( 'wgCurRevisionId' ) == oldRevId
 221+ && mw.config.exists( 'wgPageName' ) )
 222+ {
 223+ queryParams.page = mw.config.get( 'wgPageName' );
 224+ } else {
 225+ queryParams.oldid = oldRevId;
 226+ }
 227+
 228+ var call = $.ajax({
 229+ url: mw.config.get( 'wgScriptPath' ) + '/api.php',
 230+ data: queryParams,
 231+ dataType: 'json',
 232+ success: function( result ) {
 233+ if ( !result || !result.parse ) {
 234+ return;
 235+ }
 236+ // Get data
 237+ var parse = result.parse,
 238+ text = parse.text,
 239+ languageshtml = parse.languageshtml,
 240+ categoryhtml = parse.categorieshtml;
 241+ // Insert data into page
 242+ if ( text && text['*'] ) {
 243+ $frRevContents.empty().append( text['*'] );
 244+ } else {
 245+ $frRevContents.empty().append( revContent.error + ' ' + origContents );
 246+ }
 247+ if ( languageshtml && languageshtml['*'] ) {
 248+ $frRevContents.append( '<div class="langlinks" >' +
 249+ languageshtml['*'] + '</div>' );
 250+ }
 251+ if ( categoryhtml && categoryhtml['*'] ) {
 252+ $('#catlinks').replaceWith( $(categoryhtml['*']) );
 253+ }
 254+ },
 255+ error: function(xhttp, status, error) {
 256+ $frRevContents.html( revContent.error + ' ' + origContents );
 257+ }
 258+ });
 259+ }
 260+ $prevLink.click( function() {
 261+ if ( call ) {
 262+ call.abort();
 263+ }
 264+ } );
 265+ $nextLink.click( function() {
 266+ if ( call ) {
 267+ call.abort();
 268+ }
 269+ } );
 270+};
 271+
 272+// Perform some onload (which is when this script is included) events:
 273+FlaggedRevs.enableShowhide();
 274+FlaggedRevs.setCheckTrigger();
 275+FlaggedRevs.getRevisionContents();
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/flaggedrevs.js
___________________________________________________________________
Added: svn:eol-style
1276 + native
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/doc-magnify.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/doc-magnify.png
___________________________________________________________________
Added: svn:mime-type
2277 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/lock-closed.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/lock-closed.png
___________________________________________________________________
Added: svn:mime-type
3278 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/arrow-down.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/arrow-down.png
___________________________________________________________________
Added: svn:mime-type
4279 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/1.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/1.png
___________________________________________________________________
Added: svn:mime-type
5280 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/2.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/2.png
___________________________________________________________________
Added: svn:mime-type
6281 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/checkmark-orange.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/checkmark-orange.png
___________________________________________________________________
Added: svn:mime-type
7282 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/3.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/3.png
___________________________________________________________________
Added: svn:mime-type
8283 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/bar_20.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/bar_20.png
___________________________________________________________________
Added: svn:mime-type
9284 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/fr-marker-20.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/fr-marker-20.png
___________________________________________________________________
Added: svn:mime-type
10285 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/fr-marker-40.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/fr-marker-40.png
___________________________________________________________________
Added: svn:mime-type
11286 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/bar_40.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/bar_40.png
___________________________________________________________________
Added: svn:mime-type
12287 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/fr-marker-60.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/fr-marker-60.png
___________________________________________________________________
Added: svn:mime-type
13288 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/bar_60.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/bar_60.png
___________________________________________________________________
Added: svn:mime-type
14289 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/fr-marker-80.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/fr-marker-80.png
___________________________________________________________________
Added: svn:mime-type
15290 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/bar_80.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/bar_80.png
___________________________________________________________________
Added: svn:mime-type
16291 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/arrow-up.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/arrow-up.png
___________________________________________________________________
Added: svn:mime-type
17292 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/license.txt
@@ -0,0 +1,5 @@
 2+All images in this folder are available under the
 3+GNU Free Documentation license (1.2+).
 4+
 5+All the images are to be credited to Joerg Baach, except for lock-open.png and lock-closed.png,
 6+which where created by "Jasu" (http://commons.wikimedia.org/wiki/User:Jasu), under the same license.
\ No newline at end of file
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/license.txt
___________________________________________________________________
Added: svn:eol-style
17 + native
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/doc-check.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/doc-check.png
___________________________________________________________________
Added: svn:mime-type
28 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/fr-marker-100.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/fr-marker-100.png
___________________________________________________________________
Added: svn:mime-type
39 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/bar_100.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/bar_100.png
___________________________________________________________________
Added: svn:mime-type
410 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/checkmark-green.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/checkmark-green.png
___________________________________________________________________
Added: svn:mime-type
511 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/img/lock-open.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/img/lock-open.png
___________________________________________________________________
Added: svn:mime-type
612 + image/png
Index: trunk/extensions/FlaggedRevs/presentation/modules/review.js
@@ -0,0 +1,322 @@
 2+/**
 3+ * FlaggedRevs Stylesheet
 4+ * @author Aaron Schulz
 5+ * @author Daniel Arnold 2008
 6+ */
 7+
 8+window.FlaggedRevsReview = {
 9+ /*
 10+ * Updates for radios/checkboxes on patch by Daniel Arnold (bug 13744).
 11+ * Visually update the revision rating form on change.
 12+ * - Disable submit in case of invalid input.
 13+ * - Update colors when <select> changes.
 14+ * - Also remove comment box clutter in case of invalid input.
 15+ * NOTE: all buttons should exist (perhaps hidden though)
 16+ */
 17+ 'updateRatingForm': function() {
 18+ var ratingform = document.getElementById('mw-fr-ratingselects');
 19+ if( !ratingform ) return;
 20+ var disabled = document.getElementById('fr-rating-controls-disabled');
 21+ if( disabled ) return;
 22+
 23+ var quality = true;
 24+ var somezero = false;
 25+
 26+ // Determine if this is a "quality" or "incomplete" review
 27+ for( tag in wgFlaggedRevsParams.tags ) {
 28+ var controlName = "wp" + tag;
 29+ var levels = document.getElementsByName(controlName);
 30+ if( !levels.length ) continue;
 31+
 32+ var selectedlevel = 0; // default
 33+ if( levels[0].nodeName == 'SELECT' ) {
 34+ selectedlevel = levels[0].selectedIndex;
 35+ } else if( levels[0].type == 'radio' ) {
 36+ for( i = 0; i < levels.length; i++ ) {
 37+ if( levels[i].checked ) {
 38+ selectedlevel = i;
 39+ break;
 40+ }
 41+ }
 42+ } else if( levels[0].type == 'checkbox' ) {
 43+ selectedlevel = (levels[0].checked) ? 1: 0;
 44+ } else {
 45+ return; // error: should not happen
 46+ }
 47+
 48+ // Get quality level for this tag
 49+ qualityLevel = wgFlaggedRevsParams.tags[tag]['quality'];
 50+
 51+ if( selectedlevel < qualityLevel ) {
 52+ quality = false; // not a quality review
 53+ }
 54+ if( selectedlevel <= 0 ) {
 55+ somezero = true;
 56+ }
 57+ }
 58+
 59+ // (a) If only a few levels are zero ("incomplete") then disable submission.
 60+ // (b) Re-enable submission for already accepted revs when ratings change.
 61+ var asubmit = document.getElementById('mw-fr-submit-accept');
 62+ if( asubmit ) {
 63+ asubmit.disabled = somezero ? 'disabled' : '';
 64+ asubmit.value = mediaWiki.msg('revreview-submit-review'); // reset to "Accept"
 65+ }
 66+
 67+ // Update colors of <select>
 68+ FlaggedRevsReview.updateRatingFormColors( ratingform );
 69+ },
 70+
 71+ /*
 72+ * Update <select> color for the selected item
 73+ */
 74+ 'updateRatingFormColors': function() {
 75+ for( tag in wgFlaggedRevsParams.tags ) {
 76+ var controlName = "wp" + tag;
 77+ var levels = document.getElementsByName(controlName);
 78+ if( levels.length && levels[0].nodeName == 'SELECT' ) {
 79+ selectedlevel = levels[0].selectedIndex;
 80+ value = levels[0].getElementsByTagName('option')[selectedlevel].value;
 81+ levels[0].className = 'fr-rating-option-' + value;
 82+ }
 83+ }
 84+ },
 85+
 86+ /*
 87+ * Disable 'accept' button if the revision was already reviewed
 88+ * NOTE: this is used so that they can be re-enabled if a rating changes
 89+ */
 90+ 'maybeDisableAcceptButton': function() {
 91+ if( typeof(jsReviewNeedsChange) != 'undefined' && jsReviewNeedsChange == 1 ) {
 92+ var asubmit = document.getElementById('mw-fr-submit-accept');
 93+ if( asubmit ) {
 94+ asubmit.disabled = 'disabled';
 95+ }
 96+ }
 97+ },
 98+
 99+ /*
 100+ * Enable AJAX-based submit functionality to the review form on this page
 101+ */
 102+ 'enableAjaxReview': function() {
 103+ var asubmit = document.getElementById("mw-fr-submit-accept");
 104+ if( asubmit ) {
 105+ asubmit.onclick = FlaggedRevsReview.submitRevisionReview;
 106+ }
 107+ var usubmit = document.getElementById("mw-fr-submit-unaccept");
 108+ if( usubmit ) {
 109+ usubmit.onclick = FlaggedRevsReview.submitRevisionReview;
 110+ }
 111+ },
 112+
 113+ /*
 114+ * Lock review form from submissions (using during AJAX requests)
 115+ */
 116+ 'lockReviewForm': function( form ) {
 117+ var inputs = form.getElementsByTagName("input");
 118+ for( var i=0; i < inputs.length; i++) {
 119+ inputs[i].disabled = "disabled";
 120+ }
 121+ var textareas = document.getElementsByTagName("textarea");
 122+ for( var i=0; i < textareas.length; i++) {
 123+ textareas[i].disabled = "disabled";
 124+ }
 125+ var selects = form.getElementsByTagName("select");
 126+ for( var i=0; i < selects.length; i++) {
 127+ selects[i].disabled = "disabled";
 128+ }
 129+ },
 130+
 131+ /*
 132+ * Unlock review form from submissions (using after AJAX requests)
 133+ */
 134+ 'unlockReviewForm': function( form ) {
 135+ var inputs = form.getElementsByTagName("input");
 136+ for( var i=0; i < inputs.length; i++) {
 137+ if( inputs[i].type != 'submit' ) { // not all buttons can be enabled
 138+ inputs[i].disabled = "";
 139+ } else {
 140+ inputs[i].blur(); // focus off element (bug 24013)
 141+ }
 142+ }
 143+ var textareas = document.getElementsByTagName("textarea");
 144+ for( var i=0; i < textareas.length; i++) {
 145+ textareas[i].disabled = "";
 146+ }
 147+ var selects = form.getElementsByTagName("select");
 148+ for( var i=0; i < selects.length; i++) {
 149+ selects[i].disabled = "";
 150+ }
 151+ },
 152+
 153+ /*
 154+ * Submit a revision review via AJAX and update form elements.
 155+ *
 156+ * Note: requestArgs build-up from radios/checkboxes
 157+ * based on patch by Daniel Arnold (bug 13744)
 158+ */
 159+ 'submitRevisionReview': function() {
 160+ var form = document.getElementById("mw-fr-reviewform");
 161+ if( !form ) {
 162+ return true; // do normal behavoir (shouldn't happen)
 163+ }
 164+ FlaggedRevsReview.lockReviewForm( form ); // disallow submissions
 165+
 166+ var notes = document.getElementById("wpNotes");
 167+ // Build up arguments array and update submit button text...
 168+ var requestArgs = []; // array of strings of the format <"pname|pval">.
 169+ var inputs = form.getElementsByTagName("input");
 170+ for( var i=0; i < inputs.length; i++) {
 171+ // Different input types may occur depending on tags...
 172+ if( inputs[i].name == "title" || inputs[i].name == "action" ) {
 173+ continue; // No need to send these...
 174+ } else if( inputs[i].type == "submit" ) {
 175+ if( inputs[i].id == this.id ) {
 176+ requestArgs.push( inputs[i].name + "|1" );
 177+ // Show that we are submitting via this button
 178+ inputs[i].value = mediaWiki.msg('revreview-submitting');
 179+ }
 180+ } else if( inputs[i].type == "checkbox" ) {
 181+ requestArgs.push( inputs[i].name + "|" +
 182+ (inputs[i].checked ? inputs[i].value : 0) );
 183+ } else if( inputs[i].type == "radio" ) {
 184+ if( inputs[i].checked ) { // must be checked
 185+ requestArgs.push( inputs[i].name + "|" + inputs[i].value );
 186+ }
 187+ } else {
 188+ requestArgs.push( inputs[i].name + "|" + inputs[i].value ); // text/hiddens...
 189+ }
 190+ }
 191+ if( notes ) {
 192+ requestArgs.push( notes.name + "|" + notes.value );
 193+ }
 194+ var selects = form.getElementsByTagName("select");
 195+ for( var i=0; i < selects.length; i++) {
 196+ // Get the selected tag level...
 197+ if( selects[i].selectedIndex >= 0 ) {
 198+ var soption = selects[i].getElementsByTagName("option")[selects[i].selectedIndex];
 199+ requestArgs.push( selects[i].name + "|" + soption.value );
 200+ }
 201+ }
 202+ // Send encoded function plus all arguments...
 203+ post_data = 'action=ajax&rs=RevisionReview::AjaxReview';
 204+ for( var i=0; i<requestArgs.length; i++ ) {
 205+ post_data += '&rsargs[]=' + encodeURIComponent( requestArgs[i] );
 206+ }
 207+ // Send POST request via AJAX!
 208+ var call = jQuery.ajax({
 209+ url : wgScriptPath + '/index.php',
 210+ type : "POST",
 211+ data : post_data,
 212+ dataType: "html", // response type
 213+ success : function( response ) {
 214+ FlaggedRevsReview.updateReviewForm( form, response ); },
 215+ error : function( response ) {
 216+ FlaggedRevsReview.unlockReviewForm( form ); }
 217+ });
 218+ return false; // don't do normal non-AJAX submit
 219+ },
 220+
 221+ 'updateReviewForm': function( form, response ) {
 222+ var msg = response.substr(6); // remove <err#> or <suc#>
 223+ // Read new "last change time" timestamp for conflict handling
 224+ // @TODO: pass last-chage-time data using JSON or something not retarded
 225+ var m = msg.match(/^<lct#(\d*)>(.*)/m);
 226+ if( m ) msg = m[2]; // remove tag from msg
 227+ var changeTime = m ? m[1] : null; // MW TS
 228+ // Some form elements...
 229+ var asubmit = document.getElementById('mw-fr-submit-accept');
 230+ var usubmit = document.getElementById('mw-fr-submit-unaccept');
 231+ var legend = document.getElementById('mw-fr-reviewformlegend');
 232+ var diffNotice = document.getElementById('mw-fr-difftostable');
 233+ var tagBox = document.getElementById('mw-fr-revisiontag');
 234+ // On success...
 235+ if( response.indexOf('<suc#>') == 0 ) {
 236+ // (a) Update document title and form buttons...
 237+ document.title = mediaWiki.msg('actioncomplete');
 238+ if( asubmit && usubmit ) {
 239+ // Revision was flagged
 240+ if( asubmit.value == mediaWiki.msg('revreview-submitting') ) {
 241+ asubmit.value = mediaWiki.msg('revreview-submit-reviewed'); // done!
 242+ asubmit.style.fontWeight = 'bold';
 243+ // Unlock and reset *unflag* button
 244+ usubmit.value = mediaWiki.msg('revreview-submit-unreview');
 245+ usubmit.removeAttribute( 'style' ); // back to normal
 246+ usubmit.disabled = '';
 247+ // Revision was unflagged
 248+ } else if( usubmit.value == mediaWiki.msg('revreview-submitting') ) {
 249+ usubmit.value = mediaWiki.msg('revreview-submit-unreviewed'); // done!
 250+ usubmit.style.fontWeight = 'bold';
 251+ // Unlock and reset *flag* button
 252+ asubmit.value = mediaWiki.msg('revreview-submit-review');
 253+ asubmit.removeAttribute( 'style' ); // back to normal
 254+ asubmit.disabled = '';
 255+ }
 256+ }
 257+ // (b) Remove review tag from drafts
 258+ if( tagBox ) tagBox.style.display = 'none';
 259+ // (c) Update diff-related items...
 260+ var diffUIParams = document.getElementById('mw-fr-diff-dataform');
 261+ if( diffUIParams ) {
 262+ // Hide "review this" box on diffs
 263+ if( diffNotice ) diffNotice.style.display = 'none';
 264+ // Update the contents of the mw-fr-diff-headeritems div
 265+ var requestArgs = []; // <oldid, newid>
 266+ requestArgs.push( diffUIParams.getElementsByTagName('input')[0].value );
 267+ requestArgs.push( diffUIParams.getElementsByTagName('input')[1].value );
 268+ // Send encoded function plus all arguments...
 269+ url_pars = '?action=ajax&rs=FlaggedArticleView::AjaxBuildDiffHeaderItems';
 270+ for( var i=0; i<requestArgs.length; i++ ) {
 271+ url_pars += '&rsargs[]=' + encodeURIComponent(requestArgs[i]);
 272+ }
 273+ // Send GET request via AJAX!
 274+ var call = jQuery.ajax({
 275+ url : wgScriptPath + '/index.php' + url_pars,
 276+ type : "GET",
 277+ dataType: "html", // response type
 278+ success : FlaggedRevsReview.processDiffHeaderItemsResult
 279+ });
 280+ }
 281+ // On failure...
 282+ } else {
 283+ // (a) Update document title and form buttons...
 284+ document.title = mediaWiki.msg('actionfailed');
 285+ if( asubmit && usubmit ) {
 286+ // Revision was flagged
 287+ if( asubmit.value == mediaWiki.msg('revreview-submitting') ) {
 288+ asubmit.value = mediaWiki.msg('revreview-submit-review'); // back to normal
 289+ asubmit.disabled = ''; // unlock flag button
 290+ // Revision was unflagged
 291+ } else if( usubmit.value == mediaWiki.msg('revreview-submitting') ) {
 292+ usubmit.value = mediaWiki.msg('revreview-submit-unreview'); // back to normal
 293+ usubmit.disabled = ''; // unlock
 294+ }
 295+ }
 296+ // (b) Output any error response message
 297+ if( response.indexOf('<err#>') == 0 ) {
 298+ mediaWiki.util.jsMessage( msg, 'review' ); // failure notice
 299+ } else {
 300+ mediaWiki.util.jsMessage( response, 'review' ); // fatal notice
 301+ }
 302+ window.scroll(0,0); // scroll up to notice
 303+ }
 304+ // Update changetime for conflict handling
 305+ if( changeTime != null ) {
 306+ document.getElementById('mw-fr-input-changetime').value = changeTime;
 307+ }
 308+ FlaggedRevsReview.unlockReviewForm( form );
 309+ },
 310+
 311+ // update the contents of the mw-fr-diff-headeritems div
 312+ 'processDiffHeaderItemsResult': function( response ) {
 313+ var diffHeaderItems = document.getElementById("mw-fr-diff-headeritems");
 314+ if( diffHeaderItems && response != '' ) {
 315+ diffHeaderItems.innerHTML = response;
 316+ }
 317+ }
 318+};
 319+
 320+// Perform some onload (which is when this script is included) events:
 321+FlaggedRevsReview.maybeDisableAcceptButton();
 322+FlaggedRevsReview.updateRatingFormColors();
 323+FlaggedRevsReview.enableAjaxReview();
Property changes on: trunk/extensions/FlaggedRevs/presentation/modules/review.js
___________________________________________________________________
Added: svn:eol-style
1324 + native

Follow-up revisions

RevisionCommit summaryAuthorDate
r85769Follow-up r85750: forgot to update styleUrlPath()aaron20:15, 10 April 2011

Status & tagging log