Merge "Enable users to watch category membership changes #2"
[lhc/web/wiklou.git] / includes / changes / EnhancedChangesList.php
index e5916bd..b59437e 100644 (file)
@@ -83,15 +83,16 @@ class EnhancedChangesList extends ChangesList {
        /**
         * Format a line for enhanced recentchange (aka with javascript and block of lines).
         *
-        * @param RecentChange $baseRC
+        * @param RecentChange $rc
         * @param bool $watched
+        * @param int $linenumber (default null)
         *
         * @return string
         */
-       public function recentChangesLine( &$baseRC, $watched = false ) {
+       public function recentChangesLine( &$rc, $watched = false, $linenumber = null ) {
 
                $date = $this->getLanguage()->userDate(
-                       $baseRC->mAttribs['rc_timestamp'],
+                       $rc->mAttribs['rc_timestamp'],
                        $this->getUser()
                );
 
@@ -106,7 +107,7 @@ class EnhancedChangesList extends ChangesList {
                        $this->lastdate = $date;
                }
 
-               $cacheEntry = $this->cacheEntryFactory->newFromRecentChange( $baseRC, $watched );
+               $cacheEntry = $this->cacheEntryFactory->newFromRecentChange( $rc, $watched );
                $this->addCacheEntry( $cacheEntry );
 
                return $ret;
@@ -270,6 +271,24 @@ class EnhancedChangesList extends ChangesList {
 
                $queryParams['curid'] = $curId;
 
+               # Sub-entries
+               $lines = '';
+               foreach ( $block as $i => $rcObj ) {
+                       $line = $this->getLineData( $block, $rcObj, $queryParams );
+                       $lines .= $line;
+                       if ( !$line ) {
+                               // completely ignore this RC entry if we don't want to render it
+                               unset( $block[$i] );
+                       }
+               }
+               // Further down are some assumptions that $block is a 0-indexed array
+               // with (count-1) as last key. Let's make sure it is.
+               $block = array_values( $block );
+               if ( empty( $block ) ) {
+                       // if we can't show anything, don't display this block altogether
+                       return '';
+               }
+
                $r .= $this->getLogText( $block, $queryParams, $allLogs, $isnew, $namehidden );
 
                $r .= ' <span class="mw-changeslist-separator">. .</span> ';
@@ -299,116 +318,135 @@ class EnhancedChangesList extends ChangesList {
                $r .= $this->numberofWatchingusers( $block[0]->numberofWatchingusers );
                $r .= '</td></tr>';
 
-               # Sub-entries
-               foreach ( $block as $rcObj ) {
-                       # Classes to apply -- TODO implement
-                       $classes = array();
-                       $type = $rcObj->mAttribs['rc_type'];
-                       $data = array();
-
-                       $trClass = $rcObj->watched && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched
-                               ? ' class="mw-enhanced-watched"' : '';
-                       $separator = ' <span class="mw-changeslist-separator">. .</span> ';
-
-                       $data['recentChangesFlags'] = array(
-                               'newpage' => $type == RC_NEW,
-                               'minor' => $rcObj->mAttribs['rc_minor'],
-                               'unpatrolled' => $rcObj->unpatrolled,
-                               'bot' => $rcObj->mAttribs['rc_bot'],
-                       );
+               if ( !$lines ) {
+                       // if there are no lines to be rendered (all aborted by hook), don't render the block
+                       return '';
+               }
 
-                       $params = $queryParams;
+               $r .= $lines;
+               $r .= "</table>\n";
 
-                       if ( $rcObj->mAttribs['rc_this_oldid'] != 0 ) {
-                               $params['oldid'] = $rcObj->mAttribs['rc_this_oldid'];
-                       }
+               $this->rcCacheIndex++;
+
+               return $r;
+       }
 
-                       # Log timestamp
-                       if ( $type == RC_LOG ) {
-                               $link = $rcObj->timestamp;
+       /**
+        * @param RCCacheEntry[] $block
+        * @param RCCacheEntry $rcObj
+        * @param array $queryParams
+        * @return string
+        * @throws Exception
+        * @throws FatalError
+        * @throws MWException
+        */
+       protected function getLineData( array $block, RCCacheEntry $rcObj, array $queryParams = array() ) {
+               $RCShowChangedSize = $this->getConfig()->get( 'RCShowChangedSize' );
+
+               # Classes to apply -- TODO implement
+               $classes = array();
+               $type = $rcObj->mAttribs['rc_type'];
+               $data = array();
+
+               $trClass = $rcObj->watched && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched
+                       ? ' class="mw-enhanced-watched"' : '';
+               $separator = ' <span class="mw-changeslist-separator">. .</span> ';
+
+               $data['recentChangesFlags'] = array(
+                       'newpage' => $type == RC_NEW,
+                       'minor' => $rcObj->mAttribs['rc_minor'],
+                       'unpatrolled' => $rcObj->unpatrolled,
+                       'bot' => $rcObj->mAttribs['rc_bot'],
+               );
+
+               $params = $queryParams;
+
+               if ( $rcObj->mAttribs['rc_this_oldid'] != 0 ) {
+                       $params['oldid'] = $rcObj->mAttribs['rc_this_oldid'];
+               }
+
+               # Log timestamp
+               if ( $type == RC_LOG ) {
+                       $link = $rcObj->timestamp;
                        # Revision link
-                       } elseif ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ) {
-                               $link = '<span class="history-deleted">' . $rcObj->timestamp . '</span> ';
-                       } else {
-                               $link = Linker::linkKnown(
-                                       $rcObj->getTitle(),
-                                       $rcObj->timestamp,
-                                       array(),
-                                       $params
-                               );
-                               if ( $this->isDeleted( $rcObj, Revision::DELETED_TEXT ) ) {
-                                       $link = '<span class="history-deleted">' . $link . '</span> ';
-                               }
+               } elseif ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ) {
+                       $link = '<span class="history-deleted">' . $rcObj->timestamp . '</span> ';
+               } else {
+                       $link = Linker::linkKnown(
+                               $rcObj->getTitle(),
+                               $rcObj->timestamp,
+                               array(),
+                               $params
+                       );
+                       if ( $this->isDeleted( $rcObj, Revision::DELETED_TEXT ) ) {
+                               $link = '<span class="history-deleted">' . $link . '</span> ';
                        }
-                       $data['timestampLink'] = $link;
+               }
+               $data['timestampLink'] = $link;
 
-                       $currentAndLastLinks = '';
-                       if ( !$type == RC_LOG || $type == RC_NEW ) {
-                               $currentAndLastLinks .= ' ' . $this->msg( 'parentheses' )->rawParams(
+               $currentAndLastLinks = '';
+               if ( !$type == RC_LOG || $type == RC_NEW ) {
+                       $currentAndLastLinks .= ' ' . $this->msg( 'parentheses' )->rawParams(
                                        $rcObj->curlink .
-                                               $this->message['pipe-separator'] .
-                                               $rcObj->lastlink
+                                       $this->message['pipe-separator'] .
+                                       $rcObj->lastlink
                                )->escaped();
-                       }
-                       $data['currentAndLastLinks'] = $currentAndLastLinks;
-                       $data['separatorAfterCurrentAndLastLinks'] = $separator;
-
-                       # Character diff
-                       if ( $RCShowChangedSize ) {
-                               $cd = $this->formatCharacterDifference( $rcObj );
-                               if ( $cd !== '' ) {
-                                       $data['characterDiff'] = $cd;
-                                       $data['separatorAfterCharacterDiff'] = $separator;
-                               }
-                       }
+               }
+               $data['currentAndLastLinks'] = $currentAndLastLinks;
+               $data['separatorAfterCurrentAndLastLinks'] = $separator;
 
-                       if ( $rcObj->mAttribs['rc_type'] == RC_LOG ) {
-                               $data['logEntry'] = $this->insertLogEntry( $rcObj );
-                       } else {
-                               # User links
-                               $data['userLink'] = $rcObj->userlink;
-                               $data['userTalkLink'] = $rcObj->usertalklink;
-                               $data['comment'] = $this->insertComment( $rcObj );
+               # Character diff
+               if ( $RCShowChangedSize ) {
+                       $cd = $this->formatCharacterDifference( $rcObj );
+                       if ( $cd !== '' ) {
+                               $data['characterDiff'] = $cd;
+                               $data['separatorAfterCharacterDiff'] = $separator;
                        }
+               }
 
-                       # Rollback
-                       $data['rollback'] = $this->getRollback( $rcObj );
-
-                       # Tags
-                       $data['tags'] = $this->getTags( $rcObj, $classes );
-
-                       // give the hook a chance to modify the data
-                       $success = Hooks::run( 'EnhancedChangesListModifyLineData',
-                               array( $this, &$data, $block, $rcObj ) );
-                       if ( !$success ) {
-                               // skip entry if hook aborted it
-                               continue;
-                       }
+               if ( $rcObj->mAttribs['rc_type'] == RC_LOG ) {
+                       $data['logEntry'] = $this->insertLogEntry( $rcObj );
+               } elseif ( $this->isCategorizationWithoutRevision( $rcObj ) ) {
+                       $data['comment'] = $this->insertComment( $rcObj );
+               } else {
+                       # User links
+                       $data['userLink'] = $rcObj->userlink;
+                       $data['userTalkLink'] = $rcObj->usertalklink;
+                       $data['comment'] = $this->insertComment( $rcObj );
+               }
 
-                       $line = '<tr' . $trClass . '><td></td><td class="mw-enhanced-rc">';
-                       if ( isset( $data['recentChangesFlags'] ) ) {
-                               $line .= $this->recentChangesFlags( $data['recentChangesFlags'] );
-                               unset( $data['recentChangesFlags'] );
-                       }
-                       $line .= '&#160;</td><td class="mw-enhanced-rc-nested">';
+               # Rollback
+               $data['rollback'] = $this->getRollback( $rcObj );
 
-                       if ( isset( $data['timestampLink'] ) ) {
-                               $line .= '<span class="mw-enhanced-rc-time">' . $data['timestampLink'] . '</span>';
-                               unset( $data['timestampLink'] );
-                       }
+               # Tags
+               $data['tags'] = $this->getTags( $rcObj, $classes );
 
-                       // everything else: makes it easier for extensions to add or remove data
-                       $line .= implode( '', $data );
+               // give the hook a chance to modify the data
+               $success = Hooks::run( 'EnhancedChangesListModifyLineData',
+                       array( $this, &$data, $block, $rcObj ) );
+               if ( !$success ) {
+                       // skip entry if hook aborted it
+                       return '';
+               }
 
-                       $line .= "</td></tr>\n";
+               $line = '<tr' . $trClass . '><td></td><td class="mw-enhanced-rc">';
+               if ( isset( $data['recentChangesFlags'] ) ) {
+                       $line .= $this->recentChangesFlags( $data['recentChangesFlags'] );
+                       unset( $data['recentChangesFlags'] );
+               }
+               $line .= '&#160;</td><td class="mw-enhanced-rc-nested">';
 
-                       $r .= $line;
+               if ( isset( $data['timestampLink'] ) ) {
+                       $line .= '<span class="mw-enhanced-rc-time">' . $data['timestampLink'] . '</span>';
+                       unset( $data['timestampLink'] );
                }
-               $r .= "</table>\n";
 
-               $this->rcCacheIndex++;
+               // everything else: makes it easier for extensions to add or remove data
+               $line .= implode( '', $data );
 
-               return $r;
+               $line .= "</td></tr>\n";
+
+               return $line;
        }
 
        /**
@@ -422,6 +460,10 @@ class EnhancedChangesList extends ChangesList {
         * @return string
         */
        protected function getLogText( $block, $queryParams, $allLogs, $isnew, $namehidden ) {
+               if ( empty( $block ) ) {
+                       return '';
+               }
+
                # Changes message
                static $nchanges = array();
                static $sinceLastVisitMsg = array();
@@ -458,7 +500,7 @@ class EnhancedChangesList extends ChangesList {
                /** @var $block0 RecentChange */
                $block0 = $block[0];
                $last = $block[count( $block ) - 1];
-               if ( !$allLogs ) {
+               if ( !$allLogs && $rcObj->mAttribs['rc_type'] != RC_CATEGORIZE ) {
                        if ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ) {
                                $links['total-changes'] = $nchanges[$n];
                        } elseif ( $isnew ) {
@@ -490,7 +532,7 @@ class EnhancedChangesList extends ChangesList {
                }
 
                # History
-               if ( $allLogs ) {
+               if ( $allLogs || $rcObj->mAttribs['rc_type'] == RC_CATEGORIZE ) {
                        // don't show history link for logs
                } elseif ( $namehidden || !$block0->getTitle()->exists() ) {
                        $links['history'] = $this->message['enhancedrc-history'];
@@ -566,15 +608,9 @@ class EnhancedChangesList extends ChangesList {
                }
 
                # Diff and hist links
-               if ( $type != RC_LOG ) {
+               if ( $type  == RC_LOG && $type != RC_CATEGORIZE ) {
                        $query['action'] = 'history';
-                       $data['historyLink'] = ' ' . $this->msg( 'parentheses' )
-                               ->rawParams( $rcObj->difflink . $this->message['pipe-separator'] . Linker::linkKnown(
-                                       $rcObj->getTitle(),
-                                       $this->message['hist'],
-                                       array(),
-                                       $query
-                               ) )->escaped();
+                       $data['historyLink'] = $this->getDiffHistLinks( $rcObj, $query );
                }
                $data['separatorAfterLinks'] = ' <span class="mw-changeslist-separator">. .</span> ';
 
@@ -589,10 +625,15 @@ class EnhancedChangesList extends ChangesList {
 
                if ( $type == RC_LOG ) {
                        $data['logEntry'] = $this->insertLogEntry( $rcObj );
+               } elseif ( $this->isCategorizationWithoutRevision( $rcObj ) ) {
+                       $data['comment'] = $this->insertComment( $rcObj );
                } else {
                        $data['userLink'] = $rcObj->userlink;
                        $data['userTalkLink'] = $rcObj->usertalklink;
                        $data['comment'] = $this->insertComment( $rcObj );
+                       if ( $type == RC_CATEGORIZE ) {
+                               $data['historyLink'] = $this->getDiffHistLinks( $rcObj, $query );
+                       }
                        $data['rollback'] = $this->getRollback( $rcObj );
                }
 
@@ -633,6 +674,33 @@ class EnhancedChangesList extends ChangesList {
                return $line;
        }
 
+       /**
+        * Returns value to be used in 'historyLink' element of $data param in
+        * EnhancedChangesListModifyBlockLineData hook.
+        *
+        * @since 1.27
+        *
+        * @param RCCacheEntry $rc
+        * @param array $query array of key/value pairs to append as a query string
+        * @return string HTML
+        */
+       public function getDiffHistLinks( RCCacheEntry $rc, array $query ) {
+               $pageTitle = $rc->getTitle();
+               if ( $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE ) {
+                       // For categorizations we must swap the category title with the page title!
+                       $pageTitle = Title::newFromID( $rc->getAttribute( 'rc_cur_id' ) );
+               }
+
+               $retVal = ' ' . $this->msg( 'parentheses' )
+                               ->rawParams( $rc->difflink . $this->message['pipe-separator'] . Linker::linkKnown(
+                                               $pageTitle,
+                                               $this->message['hist'],
+                                               array(),
+                                               $query
+                                       ) )->escaped();
+               return $retVal;
+       }
+
        /**
         * If enhanced RC is in use, this function takes the previously cached
         * RC lines, arranges them, and outputs the HTML