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