Merge "Add ar_id and el_id sequences for PostgreSQL"
[lhc/web/wiklou.git] / includes / changes / EnhancedChangesList.php
1 <?php
2 /**
3 * Generates a list of changes using an Enhanced system (uses javascript).
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 */
22
23 class EnhancedChangesList extends ChangesList {
24
25 protected $rc_cache;
26
27 /**
28 * Add the JavaScript file for enhanced changeslist
29 * @return String
30 */
31 public function beginRecentChangesList() {
32 $this->rc_cache = array();
33 $this->rcMoveIndex = 0;
34 $this->rcCacheIndex = 0;
35 $this->lastdate = '';
36 $this->rclistOpen = false;
37 $this->getOutput()->addModuleStyles( array(
38 'mediawiki.special.changeslist',
39 'mediawiki.special.changeslist.enhanced',
40 ) );
41 $this->getOutput()->addModules( array(
42 'jquery.makeCollapsible',
43 'mediawiki.icon',
44 ) );
45
46 return '';
47 }
48
49 /**
50 * Format a line for enhanced recentchange (aka with javascript and block of lines).
51 *
52 * @param $baseRC RecentChange
53 * @param $watched bool
54 *
55 * @return string
56 */
57 public function recentChangesLine( &$baseRC, $watched = false ) {
58 wfProfileIn( __METHOD__ );
59
60 # Create a specialised object
61 $cacheEntry = RCCacheEntry::newFromParent( $baseRC );
62
63 $curIdEq = array( 'curid' => $cacheEntry->mAttribs['rc_cur_id'] );
64
65 # If it's a new day, add the headline and flush the cache
66 $date = $this->getLanguage()->userDate(
67 $cacheEntry->mAttribs['rc_timestamp'],
68 $this->getUser()
69 );
70
71 $ret = '';
72
73 if ( $date != $this->lastdate ) {
74 # Process current cache
75 $ret = $this->recentChangesBlock();
76 $this->rc_cache = array();
77 $ret .= Xml::element( 'h4', null, $date ) . "\n";
78 $this->lastdate = $date;
79 }
80
81 # Should patrol-related stuff be shown?
82 $cacheEntry->unpatrolled = $this->showAsUnpatrolled( $cacheEntry );
83
84 $showdifflinks = true;
85
86 # Make article link
87 $type = $cacheEntry->mAttribs['rc_type'];
88 $logType = $cacheEntry->mAttribs['rc_log_type'];
89
90 // Page moves, very old style, not supported anymore
91 if ( $type == RC_MOVE || $type == RC_MOVE_OVER_REDIRECT ) {
92 // New unpatrolled pages
93 } elseif ( $cacheEntry->unpatrolled && $type == RC_NEW ) {
94 $clink = Linker::linkKnown( $cacheEntry->getTitle() );
95 // Log entries
96 } elseif ( $type == RC_LOG ) {
97 if ( $logType ) {
98 $logtitle = SpecialPage::getTitleFor( 'Log', $logType );
99 $logpage = new LogPage( $logType );
100 $logname = $logpage->getName()->escaped();
101 $clink = $this->msg( 'parentheses' )->rawParams( Linker::linkKnown( $logtitle, $logname ) )->escaped();
102 } else {
103 $clink = Linker::link( $cacheEntry->getTitle() );
104 }
105 $watched = false;
106 // Log entries (old format) and special pages
107 } elseif ( $cacheEntry->mAttribs['rc_namespace'] == NS_SPECIAL ) {
108 wfDebug( "Unexpected special page in recentchanges\n" );
109 $clink = '';
110 // Edits
111 } else {
112 $clink = Linker::linkKnown( $cacheEntry->getTitle() );
113 }
114
115 # Don't show unusable diff links
116 if ( !ChangesList::userCan( $cacheEntry, Revision::DELETED_TEXT, $this->getUser() ) ) {
117 $showdifflinks = false;
118 }
119
120 $time = $this->getLanguage()->userTime( $cacheEntry->mAttribs['rc_timestamp'], $this->getUser() );
121
122 $cacheEntry->watched = $watched;
123 $cacheEntry->link = $clink;
124 $cacheEntry->timestamp = $time;
125 $cacheEntry->numberofWatchingusers = $baseRC->numberofWatchingusers;
126
127 # Make "cur" and "diff" links. Do not use link(), it is too slow if
128 # called too many times (50% of CPU time on RecentChanges!).
129 $thisOldid = $cacheEntry->mAttribs['rc_this_oldid'];
130 $lastOldid = $cacheEntry->mAttribs['rc_last_oldid'];
131
132 $querycur = $curIdEq + array( 'diff' => '0', 'oldid' => $thisOldid );
133 $querydiff = $curIdEq + array( 'diff' => $thisOldid, 'oldid' => $lastOldid );
134
135 if ( !$showdifflinks ) {
136 $curLink = $this->message['cur'];
137 $diffLink = $this->message['diff'];
138 } elseif ( in_array( $type, array( RC_NEW, RC_LOG, RC_MOVE, RC_MOVE_OVER_REDIRECT ) ) ) {
139 if ( $type != RC_NEW ) {
140 $curLink = $this->message['cur'];
141 } else {
142 $curUrl = htmlspecialchars( $cacheEntry->getTitle()->getLinkURL( $querycur ) );
143 $curLink = "<a href=\"$curUrl\" tabindex=\"{$baseRC->counter}\">{$this->message['cur']}</a>";
144 }
145 $diffLink = $this->message['diff'];
146 } else {
147 $diffUrl = htmlspecialchars( $cacheEntry->getTitle()->getLinkURL( $querydiff ) );
148 $curUrl = htmlspecialchars( $cacheEntry->getTitle()->getLinkURL( $querycur ) );
149 $diffLink = "<a href=\"$diffUrl\" tabindex=\"{$baseRC->counter}\">{$this->message['diff']}</a>";
150 $curLink = "<a href=\"$curUrl\" tabindex=\"{$baseRC->counter}\">{$this->message['cur']}</a>";
151 }
152
153 # Make "last" link
154 if ( !$showdifflinks || !$lastOldid ) {
155 $lastLink = $this->message['last'];
156 } elseif ( in_array( $type, array( RC_LOG, RC_MOVE, RC_MOVE_OVER_REDIRECT ) ) ) {
157 $lastLink = $this->message['last'];
158 } else {
159 $lastLink = Linker::linkKnown( $cacheEntry->getTitle(), $this->message['last'],
160 array(), $curIdEq + array( 'diff' => $thisOldid, 'oldid' => $lastOldid ) );
161 }
162
163 # Make user links
164 if ( $this->isDeleted( $cacheEntry, Revision::DELETED_USER ) ) {
165 $cacheEntry->userlink = ' <span class="history-deleted">' . $this->msg( 'rev-deleted-user' )->escaped() . '</span>';
166 } else {
167 $cacheEntry->userlink = Linker::userLink(
168 $cacheEntry->mAttribs['rc_user'],
169 $cacheEntry->mAttribs['rc_user_text']
170 );
171
172 $cacheEntry->usertalklink = Linker::userToolLinks(
173 $cacheEntry->mAttribs['rc_user'],
174 $cacheEntry->mAttribs['rc_user_text']
175 );
176 }
177
178 $cacheEntry->lastlink = $lastLink;
179 $cacheEntry->curlink = $curLink;
180 $cacheEntry->difflink = $diffLink;
181
182 # Put accumulated information into the cache, for later display
183 # Page moves go on their own line
184 $title = $cacheEntry->getTitle();
185 $secureName = $title->getPrefixedDBkey();
186
187 if ( $type == RC_MOVE || $type == RC_MOVE_OVER_REDIRECT ) {
188 # Use an @ character to prevent collision with page names
189 $this->rc_cache['@@' . ( $this->rcMoveIndex++ )] = array( $cacheEntry );
190 } else {
191 # Logs are grouped by type
192 if ( $type == RC_LOG ) {
193 $secureName = SpecialPage::getTitleFor( 'Log', $logType )->getPrefixedDBkey();
194 }
195 if ( !isset( $this->rc_cache[$secureName] ) ) {
196 $this->rc_cache[$secureName] = array();
197 }
198
199 array_push( $this->rc_cache[$secureName], $cacheEntry );
200 }
201
202 wfProfileOut( __METHOD__ );
203
204 return $ret;
205 }
206
207 /**
208 * Enhanced RC group
209 * @return string
210 */
211 protected function recentChangesBlockGroup( $block ) {
212 global $wgRCShowChangedSize;
213
214 wfProfileIn( __METHOD__ );
215
216 # Add the namespace and title of the block as part of the class
217 $classes = array( 'mw-collapsible', 'mw-collapsed', 'mw-enhanced-rc' );
218 if ( $block[0]->mAttribs['rc_log_type'] ) {
219 # Log entry
220 $classes[] = Sanitizer::escapeClass( 'mw-changeslist-log-'
221 . $block[0]->mAttribs['rc_log_type'] . '-' . $block[0]->mAttribs['rc_title'] );
222 } else {
223 $classes[] = Sanitizer::escapeClass( 'mw-changeslist-ns'
224 . $block[0]->mAttribs['rc_namespace'] . '-' . $block[0]->mAttribs['rc_title'] );
225 }
226 $classes[] = $block[0]->watched && $block[0]->mAttribs['rc_timestamp'] >= $block[0]->watched
227 ? 'mw-changeslist-line-watched' : 'mw-changeslist-line-not-watched';
228 $r = Html::openElement( 'table', array( 'class' => $classes ) ) .
229 Html::openElement( 'tr' );
230
231 # Collate list of users
232 $userlinks = array();
233 # Other properties
234 $unpatrolled = false;
235 $isnew = false;
236 $allBots = true;
237 $allMinors = true;
238 $curId = $currentRevision = 0;
239 # Some catalyst variables...
240 $namehidden = true;
241 $allLogs = true;
242 foreach ( $block as $rcObj ) {
243 $oldid = $rcObj->mAttribs['rc_last_oldid'];
244 if ( $rcObj->mAttribs['rc_type'] == RC_NEW ) {
245 $isnew = true;
246 }
247 // If all log actions to this page were hidden, then don't
248 // give the name of the affected page for this block!
249 if ( !$this->isDeleted( $rcObj, LogPage::DELETED_ACTION ) ) {
250 $namehidden = false;
251 }
252 $u = $rcObj->userlink;
253 if ( !isset( $userlinks[$u] ) ) {
254 $userlinks[$u] = 0;
255 }
256 if ( $rcObj->unpatrolled ) {
257 $unpatrolled = true;
258 }
259 if ( $rcObj->mAttribs['rc_type'] != RC_LOG ) {
260 $allLogs = false;
261 }
262 # Get the latest entry with a page_id and oldid
263 # since logs may not have these.
264 if ( !$curId && $rcObj->mAttribs['rc_cur_id'] ) {
265 $curId = $rcObj->mAttribs['rc_cur_id'];
266 }
267 if ( !$currentRevision && $rcObj->mAttribs['rc_this_oldid'] ) {
268 $currentRevision = $rcObj->mAttribs['rc_this_oldid'];
269 }
270
271 if ( !$rcObj->mAttribs['rc_bot'] ) {
272 $allBots = false;
273 }
274 if ( !$rcObj->mAttribs['rc_minor'] ) {
275 $allMinors = false;
276 }
277
278 $userlinks[$u]++;
279 }
280
281 # Sort the list and convert to text
282 krsort( $userlinks );
283 asort( $userlinks );
284 $users = array();
285 foreach ( $userlinks as $userlink => $count ) {
286 $text = $userlink;
287 $text .= $this->getLanguage()->getDirMark();
288 if ( $count > 1 ) {
289 $text .= ' ' . $this->msg( 'parentheses' )->rawParams( $this->getLanguage()->formatNum( $count ) . '×' )->escaped();
290 }
291 array_push( $users, $text );
292 }
293
294 $users = ' <span class="changedby">'
295 . $this->msg( 'brackets' )->rawParams(
296 implode( $this->message['semicolon-separator'], $users )
297 )->escaped() . '</span>';
298
299 $tl = '<span class="mw-collapsible-toggle mw-collapsible-arrow mw-enhancedchanges-arrow mw-enhancedchanges-arrow-space"></span>';
300 $r .= "<td>$tl</td>";
301
302 # Main line
303 $r .= '<td class="mw-enhanced-rc">' . $this->recentChangesFlags( array(
304 'newpage' => $isnew, # show, when one have this flag
305 'minor' => $allMinors, # show only, when all have this flag
306 'unpatrolled' => $unpatrolled, # show, when one have this flag
307 'bot' => $allBots, # show only, when all have this flag
308 ) );
309
310 # Timestamp
311 $r .= '&#160;' . $block[0]->timestamp . '&#160;</td><td>';
312
313 # Article link
314 if ( $namehidden ) {
315 $r .= ' <span class="history-deleted">' . $this->msg( 'rev-deleted-event' )->escaped() . '</span>';
316 } elseif ( $allLogs ) {
317 $r .= $this->maybeWatchedLink( $block[0]->link, $block[0]->watched );
318 } else {
319 $this->insertArticleLink( $r, $block[0], $block[0]->unpatrolled, $block[0]->watched );
320 }
321
322 $r .= $this->getLanguage()->getDirMark();
323
324 $queryParams['curid'] = $curId;
325
326 # Changes message
327 static $nchanges = array();
328 static $sinceLastVisitMsg = array();
329
330 $n = count( $block );
331 if ( !isset( $nchanges[$n] ) ) {
332 $nchanges[$n] = $this->msg( 'nchanges' )->numParams( $n )->escaped();
333 }
334
335 $sinceLast = 0;
336 $unvisitedOldid = null;
337 foreach ( $block as $rcObj ) {
338 // Same logic as below inside main foreach
339 if ( $rcObj->watched && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched ) {
340 $sinceLast++;
341 $unvisitedOldid = $rcObj->mAttribs['rc_last_oldid'];
342 }
343 }
344 if ( !isset( $sinceLastVisitMsg[$sinceLast] ) ) {
345 $sinceLastVisitMsg[$sinceLast] =
346 $this->msg( 'enhancedrc-since-last-visit' )->numParams( $sinceLast )->escaped();
347 }
348
349 # Total change link
350 $r .= ' ';
351 $logtext = '';
352 if ( !$allLogs ) {
353 if ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ) {
354 $logtext .= $nchanges[$n];
355 } elseif ( $isnew ) {
356 $logtext .= $nchanges[$n];
357 } else {
358 $logtext .= Linker::link(
359 $block[0]->getTitle(),
360 $nchanges[$n],
361 array(),
362 $queryParams + array(
363 'diff' => $currentRevision,
364 'oldid' => $oldid,
365 ),
366 array( 'known', 'noclasses' )
367 );
368 if ( $sinceLast > 0 && $sinceLast < $n ) {
369 $logtext .= $this->message['pipe-separator'] . Linker::link(
370 $block[0]->getTitle(),
371 $sinceLastVisitMsg[$sinceLast],
372 array(),
373 $queryParams + array(
374 'diff' => $currentRevision,
375 'oldid' => $unvisitedOldid,
376 ),
377 array( 'known', 'noclasses' )
378 );
379 }
380 }
381 }
382
383 # History
384 if ( $allLogs ) {
385 // don't show history link for logs
386 } elseif ( $namehidden || !$block[0]->getTitle()->exists() ) {
387 $logtext .= $this->message['pipe-separator'] . $this->message['enhancedrc-history'];
388 } else {
389 $params = $queryParams;
390 $params['action'] = 'history';
391
392 $logtext .= $this->message['pipe-separator'] .
393 Linker::linkKnown(
394 $block[0]->getTitle(),
395 $this->message['enhancedrc-history'],
396 array(),
397 $params
398 );
399 }
400
401 if ( $logtext !== '' ) {
402 $r .= $this->msg( 'parentheses' )->rawParams( $logtext )->escaped();
403 }
404
405 $r .= ' <span class="mw-changeslist-separator">. .</span> ';
406
407 # Character difference (does not apply if only log items)
408 if ( $wgRCShowChangedSize && !$allLogs ) {
409 $last = 0;
410 $first = count( $block ) - 1;
411 # Some events (like logs) have an "empty" size, so we need to skip those...
412 while ( $last < $first && $block[$last]->mAttribs['rc_new_len'] === null ) {
413 $last++;
414 }
415 while ( $first > $last && $block[$first]->mAttribs['rc_old_len'] === null ) {
416 $first--;
417 }
418 # Get net change
419 $chardiff = $this->formatCharacterDifference( $block[$first], $block[$last] );
420
421 if ( $chardiff == '' ) {
422 $r .= ' ';
423 } else {
424 $r .= ' ' . $chardiff . ' <span class="mw-changeslist-separator">. .</span> ';
425 }
426 }
427
428 $r .= $users;
429 $r .= $this->numberofWatchingusers( $block[0]->numberofWatchingusers );
430
431 # Sub-entries
432 foreach ( $block as $rcObj ) {
433 # Classes to apply -- TODO implement
434 $classes = array();
435 $type = $rcObj->mAttribs['rc_type'];
436
437 $trClass = $rcObj->watched && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched
438 ? ' class="mw-enhanced-watched"' : '';
439
440 $r .= '<tr' . $trClass . '><td></td><td class="mw-enhanced-rc">';
441 $r .= $this->recentChangesFlags( array(
442 'newpage' => $type == RC_NEW,
443 'minor' => $rcObj->mAttribs['rc_minor'],
444 'unpatrolled' => $rcObj->unpatrolled,
445 'bot' => $rcObj->mAttribs['rc_bot'],
446 ) );
447 $r .= '&#160;</td><td class="mw-enhanced-rc-nested"><span class="mw-enhanced-rc-time">';
448
449 $params = $queryParams;
450
451 if ( $rcObj->mAttribs['rc_this_oldid'] != 0 ) {
452 $params['oldid'] = $rcObj->mAttribs['rc_this_oldid'];
453 }
454
455 # Log timestamp
456 if ( $type == RC_LOG ) {
457 $link = $rcObj->timestamp;
458 # Revision link
459 } elseif ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ) {
460 $link = '<span class="history-deleted">' . $rcObj->timestamp . '</span> ';
461 } else {
462
463 $link = Linker::linkKnown(
464 $rcObj->getTitle(),
465 $rcObj->timestamp,
466 array(),
467 $params
468 );
469 if ( $this->isDeleted( $rcObj, Revision::DELETED_TEXT ) ) {
470 $link = '<span class="history-deleted">' . $link . '</span> ';
471 }
472 }
473 $r .= $link . '</span>';
474
475 if ( !$type == RC_LOG || $type == RC_NEW ) {
476 $r .= ' ' . $this->msg( 'parentheses' )->rawParams( $rcObj->curlink . $this->message['pipe-separator'] . $rcObj->lastlink )->escaped();
477 }
478 $r .= ' <span class="mw-changeslist-separator">. .</span> ';
479
480 # Character diff
481 if ( $wgRCShowChangedSize ) {
482 $cd = $this->formatCharacterDifference( $rcObj );
483 if ( $cd !== '' ) {
484 $r .= $cd . ' <span class="mw-changeslist-separator">. .</span> ';
485 }
486 }
487
488 if ( $rcObj->mAttribs['rc_type'] == RC_LOG ) {
489 $r .= $this->insertLogEntry( $rcObj );
490 } else {
491 # User links
492 $r .= $rcObj->userlink;
493 $r .= $rcObj->usertalklink;
494 $r .= $this->insertComment( $rcObj );
495 }
496
497 # Rollback
498 $this->insertRollback( $r, $rcObj );
499 # Tags
500 $this->insertTags( $r, $rcObj, $classes );
501
502 $r .= "</td></tr>\n";
503 }
504 $r .= "</table>\n";
505
506 $this->rcCacheIndex++;
507
508 wfProfileOut( __METHOD__ );
509
510 return $r;
511 }
512
513 /**
514 * Generate HTML for an arrow or placeholder graphic
515 * @param string $dir one of '', 'd', 'l', 'r'
516 * @param string $alt text
517 * @param string $title text
518 * @return String: HTML "<img>" tag
519 */
520 protected function arrow( $dir, $alt = '', $title = '' ) {
521 global $wgStylePath;
522 $encUrl = htmlspecialchars( $wgStylePath . '/common/images/Arr_' . $dir . '.png' );
523 $encAlt = htmlspecialchars( $alt );
524 $encTitle = htmlspecialchars( $title );
525 return "<img src=\"$encUrl\" width=\"12\" height=\"12\" alt=\"$encAlt\" title=\"$encTitle\" />";
526 }
527
528 /**
529 * Generate HTML for a right- or left-facing arrow,
530 * depending on language direction.
531 * @return String: HTML "<img>" tag
532 */
533 protected function sideArrow() {
534 $dir = $this->getLanguage()->isRTL() ? 'l' : 'r';
535 return $this->arrow( $dir, '+', $this->msg( 'rc-enhanced-expand' )->text() );
536 }
537
538 /**
539 * Generate HTML for a down-facing arrow
540 * depending on language direction.
541 * @return String: HTML "<img>" tag
542 */
543 protected function downArrow() {
544 return $this->arrow( 'd', '-', $this->msg( 'rc-enhanced-hide' )->text() );
545 }
546
547 /**
548 * Generate HTML for a spacer image
549 * @return String: HTML "<img>" tag
550 */
551 protected function spacerArrow() {
552 return $this->arrow( '', codepointToUtf8( 0xa0 ) ); // non-breaking space
553 }
554
555 /**
556 * Enhanced RC ungrouped line.
557 *
558 * @param $rcObj RecentChange
559 * @return String: a HTML formatted line (generated using $r)
560 */
561 protected function recentChangesBlockLine( $rcObj ) {
562 global $wgRCShowChangedSize;
563
564 wfProfileIn( __METHOD__ );
565 $query['curid'] = $rcObj->mAttribs['rc_cur_id'];
566
567 $type = $rcObj->mAttribs['rc_type'];
568 $logType = $rcObj->mAttribs['rc_log_type'];
569 $classes = array( 'mw-enhanced-rc' );
570 if ( $logType ) {
571 # Log entry
572 $classes[] = Sanitizer::escapeClass( 'mw-changeslist-log-'
573 . $logType . '-' . $rcObj->mAttribs['rc_title'] );
574 } else {
575 $classes[] = Sanitizer::escapeClass( 'mw-changeslist-ns' .
576 $rcObj->mAttribs['rc_namespace'] . '-' . $rcObj->mAttribs['rc_title'] );
577 }
578 $classes[] = $rcObj->watched && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched
579 ? 'mw-changeslist-line-watched' : 'mw-changeslist-line-not-watched';
580 $r = Html::openElement( 'table', array( 'class' => $classes ) ) .
581 Html::openElement( 'tr' );
582
583 $r .= '<td class="mw-enhanced-rc"><span class="mw-enhancedchanges-arrow-space"></span>';
584 # Flag and Timestamp
585 if ( $type == RC_MOVE || $type == RC_MOVE_OVER_REDIRECT ) {
586 $r .= $this->recentChangesFlags( array() ); // no flags, but need the placeholders
587 } else {
588 $r .= $this->recentChangesFlags( array(
589 'newpage' => $type == RC_NEW,
590 'minor' => $rcObj->mAttribs['rc_minor'],
591 'unpatrolled' => $rcObj->unpatrolled,
592 'bot' => $rcObj->mAttribs['rc_bot'],
593 ) );
594 }
595 $r .= '&#160;' . $rcObj->timestamp . '&#160;</td><td>';
596 # Article or log link
597 if ( $logType ) {
598 $logPage = new LogPage( $logType );
599 $logTitle = SpecialPage::getTitleFor( 'Log', $logType );
600 $logName = $logPage->getName()->escaped();
601 $r .= $this->msg( 'parentheses' )->rawParams( Linker::linkKnown( $logTitle, $logName ) )->escaped();
602 } else {
603 $this->insertArticleLink( $r, $rcObj, $rcObj->unpatrolled, $rcObj->watched );
604 }
605 # Diff and hist links
606 if ( $type != RC_LOG ) {
607 $query['action'] = 'history';
608 $r .= ' ' . $this->msg( 'parentheses' )->rawParams( $rcObj->difflink . $this->message['pipe-separator'] . Linker::linkKnown(
609 $rcObj->getTitle(),
610 $this->message['hist'],
611 array(),
612 $query
613 ) )->escaped();
614 }
615 $r .= ' <span class="mw-changeslist-separator">. .</span> ';
616 # Character diff
617 if ( $wgRCShowChangedSize ) {
618 $cd = $this->formatCharacterDifference( $rcObj );
619 if ( $cd !== '' ) {
620 $r .= $cd . ' <span class="mw-changeslist-separator">. .</span> ';
621 }
622 }
623
624 if ( $type == RC_LOG ) {
625 $r .= $this->insertLogEntry( $rcObj );
626 } else {
627 $r .= ' ' . $rcObj->userlink . $rcObj->usertalklink;
628 $r .= $this->insertComment( $rcObj );
629 $this->insertRollback( $r, $rcObj );
630 }
631
632 # Tags
633 $this->insertTags( $r, $rcObj, $classes );
634 # Show how many people are watching this if enabled
635 $r .= $this->numberofWatchingusers( $rcObj->numberofWatchingusers );
636
637 $r .= "</td></tr></table>\n";
638
639 wfProfileOut( __METHOD__ );
640
641 return $r;
642 }
643
644 /**
645 * If enhanced RC is in use, this function takes the previously cached
646 * RC lines, arranges them, and outputs the HTML
647 *
648 * @return string
649 */
650 protected function recentChangesBlock() {
651 if ( count ( $this->rc_cache ) == 0 ) {
652 return '';
653 }
654
655 wfProfileIn( __METHOD__ );
656
657 $blockOut = '';
658 foreach ( $this->rc_cache as $block ) {
659 if ( count( $block ) < 2 ) {
660 $blockOut .= $this->recentChangesBlockLine( array_shift( $block ) );
661 } else {
662 $blockOut .= $this->recentChangesBlockGroup( $block );
663 }
664 }
665
666 wfProfileOut( __METHOD__ );
667
668 return '<div>' . $blockOut . '</div>';
669 }
670
671 /**
672 * Returns text for the end of RC
673 * If enhanced RC is in use, returns pretty much all the text
674 * @return string
675 */
676 public function endRecentChangesList() {
677 return $this->recentChangesBlock() . parent::endRecentChangesList();
678 }
679
680 }