r99038 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r99037‎ | r99038 | r99039 >
Date:19:55, 5 October 2011
Author:ialex
Status:resolved
Tags:
Comment:
Big cleanup to DifferenceEngine:
* Call Linker methods statically
* Factorised a lot of duplicate code, such as "Mark patrolled" links, revisions headers, etc.
* Removed showFirstRevision() and made that case be handled through the normal showDiffPage(). In such case, the header will look like a normal diff page, except it is centred. For this, addHeader() will now center the "new revision" header if the string passed to the "old revision" header and the diff is empty. getDiffBody() will also return an empty string if $mOldRev is false.
* Showing only one revision when the previous was not found will also ask to unhide the revision is deleted as in normal case
* Backed out code that generates the revision header from loadRevisionData() so that this function does not make a mix of backend and UI stuff. Factorised the code in getRevisionHeader().
* Lazy-load page's language and revisions IDs (in case of "prev", "next", etc. are passed) instead of doing that in constructor.
* Made a good part of links compatible with Special:ComparePages, such as navigation links, "undo", etc. that links to the title corresponding to the revision and not the given title in the constuctor.
* "Current revision as of" can also be displayed on the old revision, useful when comparing two current revisions in Special:ComparePages
* Removed navigation, undo and rollback links when comparing two different pages, this can confuses users thinking they are comparing two revisions of the same page. Also clicking on a "undo" link in such case will give "revision not found".
* Check if the user can read the revisions before sending a external editor file
Modified paths:
  • /trunk/phase3/includes/diff/DifferenceEngine.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/diff/DifferenceEngine.php
@@ -23,7 +23,6 @@
2424 * @private
2525 */
2626 var $mOldid, $mNewid;
27 - var $mOldtitle, $mNewtitle, $mPagetitle;
2827 var $mOldtext, $mNewtext;
2928 protected $mDiffLang;
3029
@@ -37,6 +36,7 @@
3837 * @var Revision
3938 */
4039 var $mOldRev, $mNewRev;
 40+ private $mRevisionsIdsLoaded = false; // Have the revisions IDs been loaded
4141 var $mRevisionsLoaded = false; // Have the revisions been loaded
4242 var $mTextLoaded = 0; // How many text blobs have been loaded, 0, 1 or 2?
4343 var $mCacheHit = false; // Was the diff fetched from cache?
@@ -52,6 +52,9 @@
5353 // readability and conserve space with many small diffs.
5454 protected $mReducedLineNumbers = false;
5555
 56+ // Link to action=markpatrolled
 57+ protected $mMarkPatrolledLink = null;
 58+
5659 protected $unhide = false; # show rev_deleted content if allowed
5760 /**#@-*/
5861
@@ -75,29 +78,8 @@
7679 }
7780 wfDebug( "DifferenceEngine old '$old' new '$new' rcid '$rcid'\n" );
7881
79 - # Default language in which the diff text is written.
80 - $this->mDiffLang = $this->mTitle->getPageLanguage();
81 -
82 - if ( 'prev' === $new ) {
83 - # Show diff between revision $old and the previous one.
84 - # Get previous one from DB.
85 - $this->mNewid = intval( $old );
86 - $this->mOldid = $this->mTitle->getPreviousRevisionID( $this->mNewid );
87 - } elseif ( 'next' === $new ) {
88 - # Show diff between revision $old and the next one.
89 - # Get next one from DB.
90 - $this->mOldid = intval( $old );
91 - $this->mNewid = $this->mTitle->getNextRevisionID( $this->mOldid );
92 - if ( false === $this->mNewid ) {
93 - # if no result, NewId points to the newest old revision. The only newer
94 - # revision is cur, which is "0".
95 - $this->mNewid = 0;
96 - }
97 - } else {
98 - $this->mOldid = intval( $old );
99 - $this->mNewid = intval( $new );
100 - wfRunHooks( 'NewDifferenceEngine', array( &$titleObj, &$this->mOldid, &$this->mNewid, $old, $new ) );
101 - }
 82+ $this->mOldid = $old;
 83+ $this->mNewid = $new;
10284 $this->mRcidMarkPatrolled = intval( $rcid ); # force it to be an integer
10385 $this->mRefreshCache = $refreshCache;
10486 $this->unhide = $unhide;
@@ -111,6 +93,17 @@
11294 }
11395
11496 /**
 97+ * @return Language
 98+ */
 99+ function getDiffLang() {
 100+ if ( $this->mDiffLang === null ) {
 101+ # Default language in which the diff text is written.
 102+ $this->mDiffLang = $this->mTitle->getPageLanguage();
 103+ }
 104+ return $this->mDiffLang;
 105+ }
 106+
 107+ /**
115108 * @return Title
116109 */
117110 function getTitle() {
@@ -128,6 +121,7 @@
129122 * @return int
130123 */
131124 function getOldid() {
 125+ $this->loadRevisionIds();
132126 return $this->mOldid;
133127 }
134128
@@ -135,6 +129,7 @@
136130 * @return Bool|int
137131 */
138132 function getNewid() {
 133+ $this->loadRevisionIds();
139134 return $this->mNewid;
140135 }
141136
@@ -180,12 +175,34 @@
181176 }
182177
183178 function showDiffPage( $diffOnly = false ) {
184 - global $wgUser, $wgOut, $wgUseExternalEditor, $wgUseRCPatrol;
 179+ global $wgUser, $wgOut, $wgRequest, $wgUseExternalEditor, $wgUseRCPatrol;
185180 wfProfileIn( __METHOD__ );
186181
187182 # Allow frames except in certain special cases
188183 $wgOut->allowClickjacking();
 184+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
189185
 186+ if ( !$this->loadRevisionData() ) {
 187+ // Sounds like a deleted revision... Let's see what we can do.
 188+ $t = $this->mTitle->getPrefixedText();
 189+ $d = wfMsgExt( 'missingarticle-diff', array( 'escape' ),
 190+ $this->deletedIdMarker( $this->mOldid ),
 191+ $this->deletedIdMarker( $this->mNewid ) );
 192+ $wgOut->setPagetitle( wfMsg( 'errorpagetitle' ) );
 193+ $wgOut->addWikiMsg( 'missing-article', "<nowiki>$t</nowiki>", "<span class='plainlinks'>$d</span>" );
 194+ wfProfileOut( __METHOD__ );
 195+ return;
 196+ }
 197+
 198+ # mOldPage might not be set, see below.
 199+ if ( !$this->mNewPage->userCanRead() || ( $this->mOldPage && !$this->mOldPage->userCanRead() ) ) {
 200+ $wgOut->loginToUse();
 201+ $wgOut->output();
 202+ $wgOut->disable();
 203+ wfProfileOut( __METHOD__ );
 204+ return;
 205+ }
 206+
190207 # If external diffs are enabled both globally and for the user,
191208 # we'll use the application/x-external-editor interface to call
192209 # an external diff tool like kompare, kdiff3, etc.
@@ -193,11 +210,12 @@
194211 global $wgCanonicalServer, $wgScript, $wgLang;
195212 $wgOut->disable();
196213 header ( "Content-type: application/x-external-editor; charset=UTF-8" );
197 - $url1 = $this->mTitle->getCanonical( array(
 214+ # This should be mOldPage, but it may not be set, see below.
 215+ $url1 = $this->mNewPage->getCanonicalURL( array(
198216 'action' => 'raw',
199217 'oldid' => $this->mOldid
200218 ) );
201 - $url2 = $this->mTitle->getCanonical( array(
 219+ $url2 = $this->mNewPage->getCanonicalURL( array(
202220 'action' => 'raw',
203221 'oldid' => $this->mNewid
204222 ) );
@@ -223,213 +241,142 @@
224242 return;
225243 }
226244
227 - if ( !$this->loadRevisionData() ) {
228 - // Sounds like a deleted revision... Let's see what we can do.
229 - $t = $this->mTitle->getPrefixedText();
230 - $d = wfMsgExt( 'missingarticle-diff', array( 'escape' ),
231 - $this->deletedIdMarker( $this->mOldid ),
232 - $this->deletedIdMarker( $this->mNewid ) );
233 - $wgOut->setPagetitle( wfMsg( 'errorpagetitle' ) );
234 - $wgOut->addWikiMsg( 'missing-article', "<nowiki>$t</nowiki>", "<span class='plainlinks'>$d</span>" );
235 - wfProfileOut( __METHOD__ );
236 - return;
 245+ $rollback = '';
 246+ $undoLink = '';
 247+
 248+ $query = array();
 249+ # Carry over 'diffonly' param via navigation links
 250+ if ( $diffOnly != $wgUser->getBoolOption( 'diffonly' ) ) {
 251+ $query['diffonly'] = $diffOnly;
237252 }
 253+ # Cascade unhide param in links for easy deletion browsing
 254+ if ( $this->unhide ) {
 255+ $query['unhide'] = 1;
 256+ }
238257
239 - wfRunHooks( 'DiffViewHeader', array( $this, $this->mOldRev, $this->mNewRev ) );
 258+ # Check if one of the revisions is deleted/suppressed
 259+ $deleted = $suppressed = false;
 260+ $allowed = $this->mNewRev->userCan( Revision::DELETED_TEXT );
240261
241 - # mOldid is false if the difference engine is called with a "vague" query for
 262+ # mOldRev is false if the difference engine is called with a "vague" query for
242263 # a diff between a version V and its previous version V' AND the version V
243264 # is the first version of that article. In that case, V' does not exist.
244 - if ( $this->mOldid === false ) {
245 - $this->showFirstRevision();
246 - $this->renderNewRevision(); // should we respect $diffOnly here or not?
247 - wfProfileOut( __METHOD__ );
248 - return;
249 - }
 265+ if ( $this->mOldRev === false ) {
 266+ wfRunHooks( 'DiffViewHeader', array( $this, $this->mOldRev, $this->mNewRev ) );
250267
251 - $oldTitle = $this->mOldPage->getPrefixedText();
252 - $newTitle = $this->mNewPage->getPrefixedText();
253 - if ( $oldTitle == $newTitle ) {
254 - $wgOut->setPageTitle( $newTitle );
255 - } else {
256 - $wgOut->setPageTitle( $oldTitle . ', ' . $newTitle );
257 - }
258 - if ( $this->mNewPage->equals( $this->mOldPage ) ) {
 268+ $sk = $wgUser->getSkin();
 269+ if ( method_exists( $sk, 'suppressQuickbar' ) ) {
 270+ $sk->suppressQuickbar();
 271+ }
 272+
 273+ $wgOut->setPageTitle( $this->mNewPage->getPrefixedText() );
259274 $wgOut->setSubtitle( wfMsgExt( 'difference', array( 'parseinline' ) ) );
 275+ $samePage = true;
 276+ $oldHeader = '';
260277 } else {
261 - $wgOut->setSubtitle( wfMsgExt( 'difference-multipage', array( 'parseinline' ) ) );
262 - }
263 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
 278+ if ( $this->mNewPage->equals( $this->mOldPage ) ) {
 279+ $wgOut->setPageTitle( $this->mNewPage->getPrefixedText() );
 280+ $wgOut->setSubtitle( wfMsgExt( 'difference', array( 'parseinline' ) ) );
 281+ $samePage = true;
 282+ } else {
 283+ $wgOut->setPageTitle( $this->mOldPage->getPrefixedText() . ', ' . $this->mNewPage->getPrefixedText() );
 284+ $wgOut->setSubtitle( wfMsgExt( 'difference-multipage', array( 'parseinline' ) ) );
 285+ $samePage = false;
 286+ }
264287
265 - if ( !$this->mOldPage->userCanRead() || !$this->mNewPage->userCanRead() ) {
266 - $wgOut->loginToUse();
267 - $wgOut->output();
268 - $wgOut->disable();
269 - wfProfileOut( __METHOD__ );
270 - return;
271 - }
 288+ if ( $samePage && $this->mNewPage->userCan( 'edit' ) ) {
 289+ if ( $this->mNewRev->isCurrent() && $this->mNewPage->userCan( 'rollback' ) ) {
 290+ $wgOut->preventClickjacking();
 291+ $rollback = '&#160;&#160;&#160;' . Linker::generateRollback( $this->mNewRev );
 292+ }
 293+ if ( !$this->mOldRev->isDeleted( Revision::DELETED_TEXT ) && !$this->mNewRev->isDeleted( Revision::DELETED_TEXT ) ) {
 294+ $undoLink = ' ' . wfMsgHtml( 'parentheses', Html::element( 'a', array(
 295+ 'href' => $this->mNewPage->getLocalUrl( array(
 296+ 'action' => 'edit',
 297+ 'undoafter' => $this->mOldid,
 298+ 'undo' => $this->mNewid ) ),
 299+ 'title' => Linker::titleAttrib( 'undo' )
 300+ ), wfMsg( 'editundo' ) ) );
 301+ }
 302+ }
272303
273 - $sk = $wgUser->getSkin();
274 - if ( method_exists( $sk, 'suppressQuickbar' ) ) {
275 - $sk->suppressQuickbar();
276 - }
277 -
278 - // Check if page is editable
279 - $editable = $this->mNewRev->getTitle()->userCan( 'edit' );
280 - if ( $editable && $this->mNewRev->isCurrent() && $wgUser->isAllowed( 'rollback' ) ) {
281 - $wgOut->preventClickjacking();
282 - $rollback = '&#160;&#160;&#160;' . $sk->generateRollback( $this->mNewRev );
283 - } else {
284 - $rollback = '';
285 - }
286 -
287 - // Prepare a change patrol link, if applicable
288 - if ( $wgUseRCPatrol && $this->mTitle->userCan( 'patrol' ) ) {
289 - // If we've been given an explicit change identifier, use it; saves time
290 - if ( $this->mRcidMarkPatrolled ) {
291 - $rcid = $this->mRcidMarkPatrolled;
292 - $rc = RecentChange::newFromId( $rcid );
293 - // Already patrolled?
294 - $rcid = is_object( $rc ) && !$rc->getAttribute( 'rc_patrolled' ) ? $rcid : 0;
295 - } else {
296 - // Look for an unpatrolled change corresponding to this diff
297 - $db = wfGetDB( DB_SLAVE );
298 - $change = RecentChange::newFromConds(
299 - array(
300 - // Redundant user,timestamp condition so we can use the existing index
301 - 'rc_user_text' => $this->mNewRev->getRawUserText(),
302 - 'rc_timestamp' => $db->timestamp( $this->mNewRev->getTimestamp() ),
303 - 'rc_this_oldid' => $this->mNewid,
304 - 'rc_last_oldid' => $this->mOldid,
305 - 'rc_patrolled' => 0
306 - ),
307 - __METHOD__
 304+ # Make "previous revision link"
 305+ if ( $samePage && $this->mOldRev->getPrevious() ) {
 306+ $prevlink = Linker::linkKnown(
 307+ $this->mOldPage,
 308+ wfMsgHtml( 'previousdiff' ),
 309+ array( 'id' => 'differences-prevlink' ),
 310+ array( 'diff' => 'prev', 'oldid' => $this->mOldid ) + $query
308311 );
309 - if ( $change instanceof RecentChange ) {
310 - $rcid = $change->mAttribs['rc_id'];
311 - $this->mRcidMarkPatrolled = $rcid;
312 - } else {
313 - // None found
314 - $rcid = 0;
315 - }
 312+ } else {
 313+ $prevlink = '&#160;';
316314 }
317 - // Build the link
318 - if ( $rcid ) {
319 - $wgOut->preventClickjacking();
320 - $token = $wgUser->editToken( $rcid );
321 - $patrol = ' <span class="patrollink">[' . $sk->link(
322 - $this->mTitle,
323 - wfMsgHtml( 'markaspatrolleddiff' ),
324 - array(),
325 - array(
326 - 'action' => 'markpatrolled',
327 - 'rcid' => $rcid,
328 - 'token' => $token,
329 - ),
330 - array(
331 - 'known',
332 - 'noclasses'
333 - )
334 - ) . ']</span>';
 315+
 316+ if ( $this->mOldRev->isMinor() ) {
 317+ $oldminor = ChangesList::flag( 'minor' );
335318 } else {
336 - $patrol = '';
 319+ $oldminor = '';
337320 }
338 - } else {
339 - $patrol = '';
340 - }
341321
342 - # Carry over 'diffonly' param via navigation links
343 - if ( $diffOnly != $wgUser->getBoolOption( 'diffonly' ) ) {
344 - $query['diffonly'] = $diffOnly;
345 - }
 322+ $ldel = $this->revisionDeleteLink( $this->mOldRev );
 323+ $oldRevisionHeader = $this->getRevisionHeader( $this->mOldRev, 'complete' );
346324
347 - # Make "previous revision link"
348 - $query['diff'] = 'prev';
349 - $query['oldid'] = $this->mOldid;
350 - # Cascade unhide param in links for easy deletion browsing
351 - if ( $this->unhide ) {
352 - $query['unhide'] = 1;
 325+ $oldHeader = '<div id="mw-diff-otitle1"><strong>' . $oldRevisionHeader . '</strong></div>' .
 326+ '<div id="mw-diff-otitle2">' .
 327+ Linker::revUserTools( $this->mOldRev, !$this->unhide ) . '</div>' .
 328+ '<div id="mw-diff-otitle3">' . $oldminor .
 329+ Linker::revComment( $this->mOldRev, !$diffOnly, !$this->unhide ) . $ldel . '</div>' .
 330+ '<div id="mw-diff-otitle4">' . $prevlink . '</div>';
 331+
 332+ if ( $this->mOldRev->isDeleted( Revision::DELETED_TEXT ) ) {
 333+ $deleted = true; // old revisions text is hidden
 334+ if ( $this->mOldRev->isDeleted( Revision::DELETED_RESTRICTED ) ) {
 335+ $suppressed = true; // also suppressed
 336+ }
 337+ }
 338+
 339+ # Check if this user can see the revisions
 340+ if ( !$this->mOldRev->userCan( Revision::DELETED_TEXT ) ) {
 341+ $allowed = false;
 342+ }
353343 }
354 - if ( !$this->mOldRev->getPrevious() ) {
355 - $prevlink = '&#160;';
356 - } else {
357 - $prevlink = $sk->link(
358 - $this->mTitle,
359 - wfMsgHtml( 'previousdiff' ),
360 - array(
361 - 'id' => 'differences-prevlink'
362 - ),
363 - $query,
364 - array(
365 - 'known',
366 - 'noclasses'
367 - )
368 - );
369 - }
370344
371345 # Make "next revision link"
372 - $query['diff'] = 'next';
373 - $query['oldid'] = $this->mNewid;
374346 # Skip next link on the top revision
375 - if ( $this->mNewRev->isCurrent() ) {
376 - $nextlink = '&#160;';
377 - } else {
378 - $nextlink = $sk->link(
379 - $this->mTitle,
 347+ if ( $samePage && !$this->mNewRev->isCurrent() ) {
 348+ $nextlink = Linker::linkKnown(
 349+ $this->mNewPage,
380350 wfMsgHtml( 'nextdiff' ),
381 - array(
382 - 'id' => 'differences-nextlink'
383 - ),
384 - $query,
385 - array(
386 - 'known',
387 - 'noclasses'
388 - )
 351+ array( 'id' => 'differences-nextlink' ),
 352+ array( 'diff' => 'next', 'oldid' => $this->mNewid ) + $query
389353 );
 354+ } else {
 355+ $nextlink = '&#160;';
390356 }
391357
392 - $oldminor = '';
393 - $newminor = '';
394 -
395 - if ( $this->mOldRev->isMinor() ) {
396 - $oldminor = ChangesList::flag( 'minor' );
397 - }
398358 if ( $this->mNewRev->isMinor() ) {
399359 $newminor = ChangesList::flag( 'minor' );
 360+ } else {
 361+ $newminor = '';
400362 }
401363
402364 # Handle RevisionDelete links...
403 - $ldel = $this->revisionDeleteLink( $this->mOldRev );
404365 $rdel = $this->revisionDeleteLink( $this->mNewRev );
 366+ $newRevisionHeader = $this->getRevisionHeader( $this->mNewRev, 'complete' ) . $undoLink;
405367
406 - $oldHeader = '<div id="mw-diff-otitle1"><strong>' . $this->mOldtitle . '</strong></div>' .
407 - '<div id="mw-diff-otitle2">' .
408 - $sk->revUserTools( $this->mOldRev, !$this->unhide ) . '</div>' .
409 - '<div id="mw-diff-otitle3">' . $oldminor .
410 - $sk->revComment( $this->mOldRev, !$diffOnly, !$this->unhide ) . $ldel . '</div>' .
411 - '<div id="mw-diff-otitle4">' . $prevlink . '</div>';
412 - $newHeader = '<div id="mw-diff-ntitle1"><strong>' . $this->mNewtitle . '</strong></div>' .
413 - '<div id="mw-diff-ntitle2">' . $sk->revUserTools( $this->mNewRev, !$this->unhide ) .
 368+ $newHeader = '<div id="mw-diff-ntitle1"><strong>' . $newRevisionHeader . '</strong></div>' .
 369+ '<div id="mw-diff-ntitle2">' . Linker::revUserTools( $this->mNewRev, !$this->unhide ) .
414370 " $rollback</div>" .
415371 '<div id="mw-diff-ntitle3">' . $newminor .
416 - $sk->revComment( $this->mNewRev, !$diffOnly, !$this->unhide ) . $rdel . '</div>' .
417 - '<div id="mw-diff-ntitle4">' . $nextlink . $patrol . '</div>';
 372+ Linker::revComment( $this->mNewRev, !$diffOnly, !$this->unhide ) . $rdel . '</div>' .
 373+ '<div id="mw-diff-ntitle4">' . $nextlink . $this->markPatrolledLink() . '</div>';
418374
419 - # Check if this user can see the revisions
420 - $allowed = $this->mOldRev->userCan( Revision::DELETED_TEXT )
421 - && $this->mNewRev->userCan( Revision::DELETED_TEXT );
422 - # Check if one of the revisions is deleted/suppressed
423 - $deleted = $suppressed = false;
424 - if ( $this->mOldRev->isDeleted( Revision::DELETED_TEXT ) ) {
425 - $deleted = true; // old revisions text is hidden
426 - if ( $this->mOldRev->isDeleted( Revision::DELETED_RESTRICTED ) )
427 - $suppressed = true; // also suppressed
428 - }
429375 if ( $this->mNewRev->isDeleted( Revision::DELETED_TEXT ) ) {
430376 $deleted = true; // new revisions text is hidden
431377 if ( $this->mNewRev->isDeleted( Revision::DELETED_RESTRICTED ) )
432378 $suppressed = true; // also suppressed
433379 }
 380+
434381 # If the diff cannot be shown due to a deleted revision, then output
435382 # the diff header and links to unhide (if available)...
436383 if ( $deleted && ( !$this->unhide || !$allowed ) ) {
@@ -443,11 +390,7 @@
444391 array( $msg ) );
445392 } else {
446393 # Give explanation and add a link to view the diff...
447 - $link = $this->mTitle->getFullUrl( array(
448 - 'diff' => $this->mNewid,
449 - 'oldid' => $this->mOldid,
450 - 'unhide' => 1
451 - ) );
 394+ $link = $this->mTitle->getFullUrl( $wgRequest->appendQueryValue( 'unhide', '1', true ) );
452395 $msg = $suppressed ? 'rev-suppressed-unhide-diff' : 'rev-deleted-unhide-diff';
453396 $wgOut->wrapWikiMsg( "<div id='mw-$msg' class='mw-warning plainlinks'>\n$1\n</div>\n", array( $msg, $link ) );
454397 }
@@ -468,6 +411,73 @@
469412 }
470413
471414 /**
 415+ * Get a link to mark the change as patrolled, or '' if there's either no
 416+ * revision to patrol or the user is not allowed to to it.
 417+ * Side effect: this method will call OutputPage::preventClickjacking()
 418+ * when a link is builded.
 419+ *
 420+ * @return String
 421+ */
 422+ protected function markPatrolledLink() {
 423+ global $wgUseRCPatrol, $wgUser, $wgOut;
 424+
 425+ if ( $this->mMarkPatrolledLink === null ) {
 426+ // Prepare a change patrol link, if applicable
 427+ if ( $wgUseRCPatrol && $this->mNewPage->userCan( 'patrol' ) ) {
 428+ // If we've been given an explicit change identifier, use it; saves time
 429+ if ( $this->mRcidMarkPatrolled ) {
 430+ $rcid = $this->mRcidMarkPatrolled;
 431+ $rc = RecentChange::newFromId( $rcid );
 432+ // Already patrolled?
 433+ $rcid = is_object( $rc ) && !$rc->getAttribute( 'rc_patrolled' ) ? $rcid : 0;
 434+ } else {
 435+ // Look for an unpatrolled change corresponding to this diff
 436+ $db = wfGetDB( DB_SLAVE );
 437+ $change = RecentChange::newFromConds(
 438+ array(
 439+ // Redundant user,timestamp condition so we can use the existing index
 440+ 'rc_user_text' => $this->mNewRev->getRawUserText(),
 441+ 'rc_timestamp' => $db->timestamp( $this->mNewRev->getTimestamp() ),
 442+ 'rc_this_oldid' => $this->mNewid,
 443+ 'rc_last_oldid' => $this->mOldid,
 444+ 'rc_patrolled' => 0
 445+ ),
 446+ __METHOD__
 447+ );
 448+ if ( $change instanceof RecentChange ) {
 449+ $rcid = $change->mAttribs['rc_id'];
 450+ $this->mRcidMarkPatrolled = $rcid;
 451+ } else {
 452+ // None found
 453+ $rcid = 0;
 454+ }
 455+ }
 456+ // Build the link
 457+ if ( $rcid ) {
 458+ $wgOut->preventClickjacking();
 459+ $token = $wgUser->editToken( $rcid );
 460+ $this->mMarkPatrolledLink = ' <span class="patrollink">[' . Linker::linkKnown(
 461+ $this->mNewPage,
 462+ wfMsgHtml( 'markaspatrolleddiff' ),
 463+ array(),
 464+ array(
 465+ 'action' => 'markpatrolled',
 466+ 'rcid' => $rcid,
 467+ 'token' => $token,
 468+ )
 469+ ) . ']</span>';
 470+ } else {
 471+ $this->mMarkPatrolledLink = '';
 472+ }
 473+ } else {
 474+ $this->mMarkPatrolledLink = '';
 475+ }
 476+ }
 477+
 478+ return $this->mMarkPatrolledLink;
 479+ }
 480+
 481+ /**
472482 * @param $rev Revision
473483 * @return String
474484 */
@@ -479,16 +489,15 @@
480490 // (a) the user can delete revisions, or
481491 // (b) the user can view deleted revision *and* this one is deleted
482492 if ( $canHide || ( $rev->getVisibility() && $wgUser->isAllowed( 'deletedhistory' ) ) ) {
483 - $sk = $wgUser->getSkin();
484493 if ( !$rev->userCan( Revision::DELETED_RESTRICTED ) ) {
485 - $link = $sk->revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
 494+ $link = Linker::revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
486495 } else {
487496 $query = array(
488497 'type' => 'revision',
489 - 'target' => $rev->mTitle->getPrefixedDbkey(),
 498+ 'target' => $rev->getTitle()->getPrefixedDBkey(),
490499 'ids' => $rev->getId()
491500 );
492 - $link = $sk->revDeleteLink( $query,
 501+ $link = Linker::revDeleteLink( $query,
493502 $rev->isDeleted( Revision::DELETED_RESTRICTED ), $canHide );
494503 }
495504 $link = '&#160;&#160;&#160;' . $link . ' ';
@@ -502,9 +511,10 @@
503512 function renderNewRevision() {
504513 global $wgOut, $wgUser;
505514 wfProfileIn( __METHOD__ );
 515+ $revHeader = $this->getRevisionHeader( $this->mNewRev );
506516 # Add "current version as of X" title
507517 $wgOut->addHTML( "<hr class='diff-hr' />
508 - <h2 class='diff-currentversion-title'>{$this->mPagetitle}</h2>\n" );
 518+ <h2 class='diff-currentversion-title'>{$revHeader}</h2>\n" );
509519 # Page content may be handled by a hooked call instead...
510520 if ( wfRunHooks( 'ArticleContentOnDiff', array( $this, $wgOut ) ) ) {
511521 # Use the current version parser cache if applicable
@@ -518,20 +528,20 @@
519529 $wgOut->setRevisionId( $this->mNewRev->getId() );
520530 $wgOut->setArticleFlag( true );
521531
522 - if ( $this->mTitle->isCssJsSubpage() || $this->mTitle->isCssOrJsPage() ) {
 532+ if ( $this->mNewPage->isCssJsSubpage() || $this->mNewPage->isCssOrJsPage() ) {
523533 // Stolen from Article::view --AG 2007-10-11
524534 // Give hooks a chance to customise the output
525535 // @TODO: standardize this crap into one function
526 - if ( wfRunHooks( 'ShowRawCssJs', array( $this->mNewtext, $this->mTitle, $wgOut ) ) ) {
 536+ if ( wfRunHooks( 'ShowRawCssJs', array( $this->mNewtext, $this->mNewPage, $wgOut ) ) ) {
527537 // Wrap the whole lot in a <pre> and don't parse
528538 $m = array();
529 - preg_match( '!\.(css|js)$!u', $this->mTitle->getText(), $m );
 539+ preg_match( '!\.(css|js)$!u', $this->mNewPage->getText(), $m );
530540 $wgOut->addHTML( "<pre class=\"mw-code mw-{$m[1]}\" dir=\"ltr\">\n" );
531541 $wgOut->addHTML( htmlspecialchars( $this->mNewtext ) );
532542 $wgOut->addHTML( "\n</pre>\n" );
533543 }
534544 } elseif ( $pCache ) {
535 - $article = new Article( $this->mTitle, 0 );
 545+ $article = new Article( $this->mNewPage, 0 );
536546 $pOutput = ParserCache::singleton()->get( $article, $wgOut->parserOptions() );
537547 if( $pOutput ) {
538548 $wgOut->addParserOutput( $pOutput );
@@ -547,92 +557,12 @@
548558 }
549559 }
550560 # Add redundant patrol link on bottom...
551 - if ( $this->mRcidMarkPatrolled && $this->mTitle->quickUserCan( 'patrol' ) ) {
552 - $sk = $wgUser->getSkin();
553 - $token = $wgUser->editToken( $this->mRcidMarkPatrolled );
554 - $wgOut->preventClickjacking();
555 - $wgOut->addHTML(
556 - "<div class='patrollink'>[" . $sk->link(
557 - $this->mTitle,
558 - wfMsgHtml( 'markaspatrolleddiff' ),
559 - array(),
560 - array(
561 - 'action' => 'markpatrolled',
562 - 'rcid' => $this->mRcidMarkPatrolled,
563 - 'token' => $token,
564 - )
565 - ) . ']</div>'
566 - );
567 - }
 561+ $wgOut->addHTML( $this->markPatrolledLink() );
568562
569563 wfProfileOut( __METHOD__ );
570564 }
571565
572566 /**
573 - * Show the first revision of an article. Uses normal diff headers in
574 - * contrast to normal "old revision" display style.
575 - */
576 - function showFirstRevision() {
577 - global $wgOut, $wgUser;
578 - wfProfileIn( __METHOD__ );
579 -
580 - # Get article text from the DB
581 - #
582 - if ( ! $this->loadNewText() ) {
583 - $t = $this->mTitle->getPrefixedText();
584 - $d = wfMsgExt( 'missingarticle-diff', array( 'escape' ),
585 - $this->deletedIdMarker( $this->mOldid ),
586 - $this->deletedIdMarker( $this->mNewid ) );
587 - $wgOut->setPagetitle( wfMsg( 'errorpagetitle' ) );
588 - $wgOut->addWikiMsg( 'missing-article', "<nowiki>$t</nowiki>", "<span class='plainlinks'>$d</span>" );
589 - wfProfileOut( __METHOD__ );
590 - return;
591 - }
592 -
593 - # Check if user is allowed to look at this page. If not, bail out.
594 - if ( !$this->mTitle->userCanRead() ) {
595 - $wgOut->loginToUse();
596 - $wgOut->output();
597 - wfProfileOut( __METHOD__ );
598 - throw new MWException( "Permission Error: you do not have access to view this page" );
599 - }
600 -
601 - # Prepare the header box
602 - #
603 - $sk = $wgUser->getSkin();
604 -
605 - $next = $this->mTitle->getNextRevisionID( $this->mNewid );
606 - if ( !$next ) {
607 - $nextlink = '';
608 - } else {
609 - $nextlink = '<br />' . $sk->link(
610 - $this->mTitle,
611 - wfMsgHtml( 'nextdiff' ),
612 - array(
613 - 'id' => 'differences-nextlink'
614 - ),
615 - array(
616 - 'diff' => 'next',
617 - 'oldid' => $this->mNewid,
618 - ),
619 - array(
620 - 'known',
621 - 'noclasses'
622 - )
623 - );
624 - }
625 - $header = "<div class=\"firstrevisionheader\" style=\"text-align: center\">" .
626 - $sk->revUserTools( $this->mNewRev ) . "<br />" . $sk->revComment( $this->mNewRev ) . $nextlink . "</div>\n";
627 -
628 - $wgOut->addHTML( $header );
629 -
630 - $wgOut->setSubtitle( wfMsgExt( 'difference', array( 'parseinline' ) ) );
631 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
632 -
633 - wfProfileOut( __METHOD__ );
634 - }
635 -
636 - /**
637567 * Get the diff text, send it to $wgOut
638568 * Returns false if the diff could not be generated, otherwise returns true
639569 *
@@ -698,8 +628,9 @@
699629 return false;
700630 }
701631 // Short-circuit
702 - if ( $this->mOldRev && $this->mNewRev
703 - && $this->mOldRev->getID() == $this->mNewRev->getID() )
 632+ // If mOldRev is false, it means that the
 633+ if ( $this->mOldRev === false || ( $this->mOldRev && $this->mNewRev
 634+ && $this->mOldRev->getID() == $this->mNewRev->getID() ) )
704635 {
705636 wfProfileOut( __METHOD__ );
706637 return '';
@@ -900,10 +831,10 @@
901832 $newRev = $this->mNewRev;
902833 }
903834
904 - $nEdits = $this->mTitle->countRevisionsBetween( $oldRev, $newRev );
 835+ $nEdits = $this->mNewPage->countRevisionsBetween( $oldRev, $newRev );
905836 if ( $nEdits > 0 ) {
906837 $limit = 100; // use diff-multi-manyusers if too many users
907 - $numUsers = $this->mTitle->countAuthorsBetween( $oldRev, $newRev, $limit );
 838+ $numUsers = $this->mNewPage->countAuthorsBetween( $oldRev, $newRev, $limit );
908839 return self::intermediateEditsMsg( $nEdits, $numUsers, $limit );
909840 }
910841 return ''; // nothing
@@ -929,6 +860,56 @@
930861 }
931862
932863 /**
 864+ * Get a header for a specified revision.
 865+ *
 866+ * @param $rev Revision
 867+ * @param $complete String: 'complete' to get the header wrapped depending
 868+ * the visibility of the revision and a link to edit the page.
 869+ * @return String HTML fragment
 870+ */
 871+ private function getRevisionHeader( Revision $rev, $complete = '' ) {
 872+ global $wgLang;
 873+
 874+ $revtimestamp = $rev->getTimestamp();
 875+ $timestamp = $wgLang->timeanddate( $revtimestamp, true );
 876+ $dateofrev = $wgLang->date( $revtimestamp, true );
 877+ $timeofrev = $wgLang->time( $revtimestamp, true );
 878+
 879+ $header = htmlspecialchars( wfMsg(
 880+ $rev->isCurrent() ? 'currentrev-asof' : 'revisionasof',
 881+ $timestamp,
 882+ $dateofrev,
 883+ $timeofrev
 884+ ) );
 885+
 886+ if ( $complete !== 'complete' ) {
 887+ return $header;
 888+ }
 889+
 890+ $title = $rev->getTitle();
 891+
 892+ $header = Linker::linkKnown( $title, $header, array(),
 893+ array( 'oldid' => $rev->getID() ) );
 894+
 895+ if ( $rev->userCan( Revision::DELETED_TEXT ) ) {
 896+ $editQuery = array( 'action' => 'edit' );
 897+ if ( !$rev->isCurrent() ) {
 898+ $editQuery['oldid'] = $rev->getID();
 899+ }
 900+
 901+ $msg = wfMsgHtml( $title->userCan( 'edit' ) ? 'editold' : 'viewsourceold' );
 902+ $header .= ' (' . Linker::linkKnown( $title, $msg, array(), $editQuery ) . ')';
 903+ if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
 904+ $header = Html::rawElement( 'span', array( 'class' => 'history-deleted' ), $header );
 905+ }
 906+ } else {
 907+ $header = Html::rawElement( 'span', array( 'class' => 'history-deleted' ), $header );
 908+ }
 909+
 910+ return $header;
 911+ }
 912+
 913+ /**
933914 * Add the header to a diff body
934915 *
935916 * @return string
@@ -936,25 +917,34 @@
937918 function addHeader( $diff, $otitle, $ntitle, $multi = '', $notice = '' ) {
938919 // shared.css sets diff in interface language/dir, but the actual content
939920 // is often in a different language, mostly the page content language/dir
940 - $tableClass = 'diff diff-contentalign-' . htmlspecialchars( $this->mDiffLang->alignStart() );
 921+ $tableClass = 'diff diff-contentalign-' . htmlspecialchars( $this->getDiffLang()->alignStart() );
941922 $header = "<table class='$tableClass'>";
942 - if ( $diff ) { // Safari/Chrome show broken output if cols not used
 923+
 924+ if ( !$diff && !$otitle ) {
943925 $header .= "
944 - <col class='diff-marker' />
945 - <col class='diff-content' />
946 - <col class='diff-marker' />
947 - <col class='diff-content' />";
948 - $colspan = 2;
949 - $multiColspan = 4;
 926+ <tr valign='top'>
 927+ <td class='diff-ntitle'>{$ntitle}</td>
 928+ </tr>";
 929+ $multiColspan = 1;
950930 } else {
951 - $colspan = 1;
952 - $multiColspan = 2;
 931+ if ( $diff ) { // Safari/Chrome show broken output if cols not used
 932+ $header .= "
 933+ <col class='diff-marker' />
 934+ <col class='diff-content' />
 935+ <col class='diff-marker' />
 936+ <col class='diff-content' />";
 937+ $colspan = 2;
 938+ $multiColspan = 4;
 939+ } else {
 940+ $colspan = 1;
 941+ $multiColspan = 2;
 942+ }
 943+ $header .= "
 944+ <tr valign='top'>
 945+ <td colspan='$colspan' class='diff-otitle'>{$otitle}</td>
 946+ <td colspan='$colspan' class='diff-ntitle'>{$ntitle}</td>
 947+ </tr>";
953948 }
954 - $header .= "
955 - <tr valign='top'>
956 - <td colspan='$colspan' class='diff-otitle'>{$otitle}</td>
957 - <td colspan='$colspan' class='diff-ntitle'>{$ntitle}</td>
958 - </tr>";
959949
960950 if ( $multi != '' ) {
961951 $header .= "<tr><td colspan='{$multiColspan}' align='center' class='diff-multi'>{$multi}</td></tr>";
@@ -986,6 +976,41 @@
987977 }
988978
989979 /**
 980+ * Load revision IDs
 981+ */
 982+ private function loadRevisionIds() {
 983+ if ( $this->mRevisionsIdsLoaded ) {
 984+ return;
 985+ }
 986+
 987+ $this->mRevisionsIdsLoaded = true;
 988+
 989+ $old = $this->mOldid;
 990+ $new = $this->mNewid;
 991+
 992+ if ( $new === 'prev' ) {
 993+ # Show diff between revision $old and the previous one.
 994+ # Get previous one from DB.
 995+ $this->mNewid = intval( $old );
 996+ $this->mOldid = $this->mTitle->getPreviousRevisionID( $this->mNewid );
 997+ } elseif ( $new === 'next' ) {
 998+ # Show diff between revision $old and the next one.
 999+ # Get next one from DB.
 1000+ $this->mOldid = intval( $old );
 1001+ $this->mNewid = $this->mTitle->getNextRevisionID( $this->mOldid );
 1002+ if ( $this->mNewid === false ) {
 1003+ # if no result, NewId points to the newest old revision. The only newer
 1004+ # revision is cur, which is "0".
 1005+ $this->mNewid = 0;
 1006+ }
 1007+ } else {
 1008+ $this->mOldid = intval( $old );
 1009+ $this->mNewid = intval( $new );
 1010+ wfRunHooks( 'NewDifferenceEngine', array( &$this->mTitle, &$this->mOldid, &$this->mNewid, $old, $new ) );
 1011+ }
 1012+ }
 1013+
 1014+ /**
9901015 * Load revision metadata for the specified articles. If newid is 0, then compare
9911016 * the old article in oldid to the current article; if oldid is 0, then
9921017 * compare the current article to the immediately previous one (ignoring the
@@ -998,73 +1023,30 @@
9991024 * @return bool
10001025 */
10011026 function loadRevisionData() {
1002 - global $wgLang, $wgUser;
 1027+ global $wgUser;
 1028+
10031029 if ( $this->mRevisionsLoaded ) {
10041030 return true;
1005 - } else {
1006 - // Whether it succeeds or fails, we don't want to try again
1007 - $this->mRevisionsLoaded = true;
10081031 }
10091032
 1033+ // Whether it succeeds or fails, we don't want to try again
 1034+ $this->mRevisionsLoaded = true;
 1035+
 1036+ $this->loadRevisionIds();
 1037+
10101038 // Load the new revision object
10111039 $this->mNewRev = $this->mNewid
10121040 ? Revision::newFromId( $this->mNewid )
10131041 : Revision::newFromTitle( $this->mTitle );
 1042+
10141043 if ( !$this->mNewRev instanceof Revision ) {
10151044 return false;
10161045 }
10171046
10181047 // Update the new revision ID in case it was 0 (makes life easier doing UI stuff)
10191048 $this->mNewid = $this->mNewRev->getId();
1020 -
1021 - // Check if page is editable
1022 - $editable = $this->mNewRev->getTitle()->userCan( 'edit' );
1023 -
1024 - // Set assorted variables
1025 - $timestamp = $wgLang->timeanddate( $this->mNewRev->getTimestamp(), true );
1026 - $dateofrev = $wgLang->date( $this->mNewRev->getTimestamp(), true );
1027 - $timeofrev = $wgLang->time( $this->mNewRev->getTimestamp(), true );
10281049 $this->mNewPage = $this->mNewRev->getTitle();
1029 - if ( $this->mNewRev->isCurrent() ) {
1030 - $newLink = $this->mNewPage->escapeLocalUrl( array(
1031 - 'oldid' => $this->mNewid
1032 - ) );
1033 - $this->mPagetitle = htmlspecialchars( wfMsg(
1034 - 'currentrev-asof',
1035 - $timestamp,
1036 - $dateofrev,
1037 - $timeofrev
1038 - ) );
1039 - $newEdit = $this->mNewPage->escapeLocalUrl( array(
1040 - 'action' => 'edit'
1041 - ) );
10421050
1043 - $this->mNewtitle = "<a href='$newLink'>{$this->mPagetitle}</a>";
1044 - $this->mNewtitle .= " (<a href='$newEdit'>" . wfMsgHtml( $editable ? 'editold' : 'viewsourceold' ) . "</a>)";
1045 - } else {
1046 - $newLink = $this->mNewPage->escapeLocalUrl( array(
1047 - 'oldid' => $this->mNewid
1048 - ) );
1049 - $newEdit = $this->mNewPage->escapeLocalUrl( array(
1050 - 'action' => 'edit',
1051 - 'oldid' => $this->mNewid
1052 - ) );
1053 - $this->mPagetitle = htmlspecialchars( wfMsg(
1054 - 'revisionasof',
1055 - $timestamp,
1056 - $dateofrev,
1057 - $timeofrev
1058 - ) );
1059 -
1060 - $this->mNewtitle = "<a href='$newLink'>{$this->mPagetitle}</a>";
1061 - $this->mNewtitle .= " (<a href='$newEdit'>" . wfMsgHtml( $editable ? 'editold' : 'viewsourceold' ) . "</a>)";
1062 - }
1063 - if ( !$this->mNewRev->userCan( Revision::DELETED_TEXT ) ) {
1064 - $this->mNewtitle = "<span class='history-deleted'>{$this->mPagetitle}</span>";
1065 - } elseif ( $this->mNewRev->isDeleted( Revision::DELETED_TEXT ) ) {
1066 - $this->mNewtitle = "<span class='history-deleted'>{$this->mNewtitle}</span>";
1067 - }
1068 -
10691051 // Load the old revision object
10701052 $this->mOldRev = false;
10711053 if ( $this->mOldid ) {
@@ -1087,38 +1069,6 @@
10881070
10891071 if ( $this->mOldRev ) {
10901072 $this->mOldPage = $this->mOldRev->getTitle();
1091 -
1092 - $t = $wgLang->timeanddate( $this->mOldRev->getTimestamp(), true );
1093 - $dateofrev = $wgLang->date( $this->mOldRev->getTimestamp(), true );
1094 - $timeofrev = $wgLang->time( $this->mOldRev->getTimestamp(), true );
1095 - $oldLink = $this->mOldPage->escapeLocalUrl( array(
1096 - 'oldid' => $this->mOldid
1097 - ) );
1098 - $oldEdit = $this->mOldPage->escapeLocalUrl( array(
1099 - 'action' => 'edit',
1100 - 'oldid' => $this->mOldid
1101 - ) );
1102 - $this->mOldPagetitle = htmlspecialchars( wfMsg( 'revisionasof', $t, $dateofrev, $timeofrev ) );
1103 -
1104 - $this->mOldtitle = "<a href='$oldLink'>{$this->mOldPagetitle}</a>"
1105 - . " (<a href='$oldEdit'>" . wfMsgHtml( $editable ? 'editold' : 'viewsourceold' ) . "</a>)";
1106 - // Add an "undo" link
1107 - if ( $editable && !$this->mOldRev->isDeleted( Revision::DELETED_TEXT ) && !$this->mNewRev->isDeleted( Revision::DELETED_TEXT ) ) {
1108 - $undoLink = Html::element( 'a', array(
1109 - 'href' => $this->mNewPage->getLocalUrl( array(
1110 - 'action' => 'edit',
1111 - 'undoafter' => $this->mOldid,
1112 - 'undo' => $this->mNewid ) ),
1113 - 'title' => $wgUser->getSkin()->titleAttrib( 'undo' )
1114 - ), wfMsg( 'editundo' ) );
1115 - $this->mNewtitle .= ' (' . $undoLink . ')';
1116 - }
1117 -
1118 - if ( !$this->mOldRev->userCan( Revision::DELETED_TEXT ) ) {
1119 - $this->mOldtitle = '<span class="history-deleted">' . $this->mOldPagetitle . '</span>';
1120 - } elseif ( $this->mOldRev->isDeleted( Revision::DELETED_TEXT ) ) {
1121 - $this->mOldtitle = '<span class="history-deleted">' . $this->mOldtitle . '</span>';
1122 - }
11231073 }
11241074
11251075 return true;

Follow-up revisions

RevisionCommit summaryAuthorDate
r99040Fix for r99038: this was in the wrong part of the if statementialex19:59, 5 October 2011
r99079And I forgot to commit this in r99038: make "unhide" parameter work in Specia...ialex08:47, 6 October 2011
r994831.18wmf1: Fix method call, part of r99038catrope15:25, 11 October 2011

Status & tagging log