Fix for r91344: removed straggling instances of $this->special in item classes
[lhc/web/wiklou.git] / includes / revisiondelete / RevisionDelete.php
1 <?php
2 /**
3 * List for revision table items
4 *
5 * This will check both the 'revision' table for live revisions and the
6 * 'archive' table for traditionally-deleted revisions that have an
7 * ar_rev_id saved.
8 *
9 * See RevDel_RevisionItem and RevDel_ArchivedRevisionItem for items.
10 */
11 class RevDel_RevisionList extends RevDel_List {
12 var $currentRevId;
13
14 public function getType() {
15 return 'revision';
16 }
17
18 public static function getRelationType() {
19 return 'rev_id';
20 }
21
22 /**
23 * @param $db DatabaseBase
24 * @return mixed
25 */
26 public function doQuery( $db ) {
27 $ids = array_map( 'intval', $this->ids );
28 $live = $db->select( array('revision','page'), '*',
29 array(
30 'rev_page' => $this->title->getArticleID(),
31 'rev_id' => $ids,
32 'rev_page = page_id'
33 ),
34 __METHOD__,
35 array( 'ORDER BY' => 'rev_id DESC' )
36 );
37
38 if ( $live->numRows() >= count( $ids ) ) {
39 // All requested revisions are live, keeps things simple!
40 return $live;
41 }
42
43 // Check if any requested revisions are available fully deleted.
44 $archived = $db->select( array( 'archive' ), '*',
45 array(
46 'ar_rev_id' => $ids
47 ),
48 __METHOD__,
49 array( 'ORDER BY' => 'ar_rev_id DESC' )
50 );
51
52 if ( $archived->numRows() == 0 ) {
53 return $live;
54 } elseif ( $live->numRows() == 0 ) {
55 return $archived;
56 } else {
57 // Combine the two! Whee
58 $rows = array();
59 foreach ( $live as $row ) {
60 $rows[$row->rev_id] = $row;
61 }
62 foreach ( $archived as $row ) {
63 $rows[$row->ar_rev_id] = $row;
64 }
65 krsort( $rows );
66 return new FakeResultWrapper( array_values( $rows ) );
67 }
68 }
69
70 public function newItem( $row ) {
71 if ( isset( $row->rev_id ) ) {
72 return new RevDel_RevisionItem( $this, $row );
73 } elseif ( isset( $row->ar_rev_id ) ) {
74 return new RevDel_ArchivedRevisionItem( $this, $row );
75 } else {
76 // This shouldn't happen. :)
77 throw new MWException( 'Invalid row type in RevDel_RevisionList' );
78 }
79 }
80
81 public function getCurrent() {
82 if ( is_null( $this->currentRevId ) ) {
83 $dbw = wfGetDB( DB_MASTER );
84 $this->currentRevId = $dbw->selectField(
85 'page', 'page_latest', $this->title->pageCond(), __METHOD__ );
86 }
87 return $this->currentRevId;
88 }
89
90 public function getSuppressBit() {
91 return Revision::DELETED_RESTRICTED;
92 }
93
94 public function doPreCommitUpdates() {
95 $this->title->invalidateCache();
96 return Status::newGood();
97 }
98
99 public function doPostCommitUpdates() {
100 $this->title->purgeSquid();
101 // Extensions that require referencing previous revisions may need this
102 wfRunHooks( 'ArticleRevisionVisibilitySet', array( &$this->title ) );
103 return Status::newGood();
104 }
105 }
106
107 /**
108 * Item class for a live revision table row
109 */
110 class RevDel_RevisionItem extends RevDel_Item {
111 var $revision;
112
113 public function __construct( $list, $row ) {
114 parent::__construct( $list, $row );
115 $this->revision = new Revision( $row );
116 }
117
118 public function getIdField() {
119 return 'rev_id';
120 }
121
122 public function getTimestampField() {
123 return 'rev_timestamp';
124 }
125
126 public function getAuthorIdField() {
127 return 'rev_user';
128 }
129
130 public function getAuthorNameField() {
131 return 'rev_user_text';
132 }
133
134 public function canView() {
135 return $this->revision->userCan( Revision::DELETED_RESTRICTED );
136 }
137
138 public function canViewContent() {
139 return $this->revision->userCan( Revision::DELETED_TEXT );
140 }
141
142 public function getBits() {
143 return $this->revision->mDeleted;
144 }
145
146 public function setBits( $bits ) {
147 $dbw = wfGetDB( DB_MASTER );
148 // Update revision table
149 $dbw->update( 'revision',
150 array( 'rev_deleted' => $bits ),
151 array(
152 'rev_id' => $this->revision->getId(),
153 'rev_page' => $this->revision->getPage(),
154 'rev_deleted' => $this->getBits()
155 ),
156 __METHOD__
157 );
158 if ( !$dbw->affectedRows() ) {
159 // Concurrent fail!
160 return false;
161 }
162 // Update recentchanges table
163 $dbw->update( 'recentchanges',
164 array(
165 'rc_deleted' => $bits,
166 'rc_patrolled' => 1
167 ),
168 array(
169 'rc_this_oldid' => $this->revision->getId(), // condition
170 // non-unique timestamp index
171 'rc_timestamp' => $dbw->timestamp( $this->revision->getTimestamp() ),
172 ),
173 __METHOD__
174 );
175 return true;
176 }
177
178 public function isDeleted() {
179 return $this->revision->isDeleted( Revision::DELETED_TEXT );
180 }
181
182 public function isHideCurrentOp( $newBits ) {
183 return ( $newBits & Revision::DELETED_TEXT )
184 && $this->list->getCurrent() == $this->getId();
185 }
186
187 /**
188 * Get the HTML link to the revision text.
189 * Overridden by RevDel_ArchiveItem.
190 */
191 protected function getRevisionLink() {
192 $date = $this->list->getLang()->timeanddate( $this->revision->getTimestamp(), true );
193 if ( $this->isDeleted() && !$this->canViewContent() ) {
194 return $date;
195 }
196 return Linker::link(
197 $this->list->title,
198 $date,
199 array(),
200 array(
201 'oldid' => $this->revision->getId(),
202 'unhide' => 1
203 )
204 );
205 }
206
207 /**
208 * Get the HTML link to the diff.
209 * Overridden by RevDel_ArchiveItem
210 */
211 protected function getDiffLink() {
212 if ( $this->isDeleted() && !$this->canViewContent() ) {
213 return wfMsgHtml('diff');
214 } else {
215 return
216 Linker::link(
217 $this->list->title,
218 wfMsgHtml('diff'),
219 array(),
220 array(
221 'diff' => $this->revision->getId(),
222 'oldid' => 'prev',
223 'unhide' => 1
224 ),
225 array(
226 'known',
227 'noclasses'
228 )
229 );
230 }
231 }
232
233 public function getHTML() {
234 $difflink = $this->getDiffLink();
235 $revlink = $this->getRevisionLink();
236 $userlink = Linker::revUserLink( $this->revision );
237 $comment = Linker::revComment( $this->revision );
238 if ( $this->isDeleted() ) {
239 $revlink = "<span class=\"history-deleted\">$revlink</span>";
240 }
241 return "<li>($difflink) $revlink $userlink $comment</li>";
242 }
243 }
244
245 /**
246 * List for archive table items, i.e. revisions deleted via action=delete
247 */
248 class RevDel_ArchiveList extends RevDel_RevisionList {
249 public function getType() {
250 return 'archive';
251 }
252
253 public static function getRelationType() {
254 return 'ar_timestamp';
255 }
256
257 /**
258 * @param $db DatabaseBase
259 * @return mixed
260 */
261 public function doQuery( $db ) {
262 $timestamps = array();
263 foreach ( $this->ids as $id ) {
264 $timestamps[] = $db->timestamp( $id );
265 }
266 return $db->select( 'archive', '*',
267 array(
268 'ar_namespace' => $this->title->getNamespace(),
269 'ar_title' => $this->title->getDBkey(),
270 'ar_timestamp' => $timestamps
271 ),
272 __METHOD__,
273 array( 'ORDER BY' => 'ar_timestamp DESC' )
274 );
275 }
276
277 public function newItem( $row ) {
278 return new RevDel_ArchiveItem( $this, $row );
279 }
280
281 public function doPreCommitUpdates() {
282 return Status::newGood();
283 }
284
285 public function doPostCommitUpdates() {
286 return Status::newGood();
287 }
288 }
289
290 /**
291 * Item class for a archive table row
292 */
293 class RevDel_ArchiveItem extends RevDel_RevisionItem {
294 public function __construct( $list, $row ) {
295 RevDel_Item::__construct( $list, $row );
296 $this->revision = Revision::newFromArchiveRow( $row,
297 array( 'page' => $this->list->title->getArticleId() ) );
298 }
299
300 public function getIdField() {
301 return 'ar_timestamp';
302 }
303
304 public function getTimestampField() {
305 return 'ar_timestamp';
306 }
307
308 public function getAuthorIdField() {
309 return 'ar_user';
310 }
311
312 public function getAuthorNameField() {
313 return 'ar_user_text';
314 }
315
316 public function getId() {
317 # Convert DB timestamp to MW timestamp
318 return $this->revision->getTimestamp();
319 }
320
321 public function setBits( $bits ) {
322 $dbw = wfGetDB( DB_MASTER );
323 $dbw->update( 'archive',
324 array( 'ar_deleted' => $bits ),
325 array(
326 'ar_namespace' => $this->list->title->getNamespace(),
327 'ar_title' => $this->list->title->getDBkey(),
328 // use timestamp for index
329 'ar_timestamp' => $this->row->ar_timestamp,
330 'ar_rev_id' => $this->row->ar_rev_id,
331 'ar_deleted' => $this->getBits()
332 ),
333 __METHOD__ );
334 return (bool)$dbw->affectedRows();
335 }
336
337 protected function getRevisionLink() {
338 $undelete = SpecialPage::getTitleFor( 'Undelete' );
339 $date = $this->list->getLang()->timeanddate( $this->revision->getTimestamp(), true );
340 if ( $this->isDeleted() && !$this->canViewContent() ) {
341 return $date;
342 }
343 return Linker::link( $undelete, $date, array(),
344 array(
345 'target' => $this->list->title->getPrefixedText(),
346 'timestamp' => $this->revision->getTimestamp()
347 ) );
348 }
349
350 protected function getDiffLink() {
351 if ( $this->isDeleted() && !$this->canViewContent() ) {
352 return wfMsgHtml( 'diff' );
353 }
354 $undelete = SpecialPage::getTitleFor( 'Undelete' );
355 return Linker::link( $undelete, wfMsgHtml('diff'), array(),
356 array(
357 'target' => $this->list->title->getPrefixedText(),
358 'diff' => 'prev',
359 'timestamp' => $this->revision->getTimestamp()
360 ) );
361 }
362 }
363
364
365 /**
366 * Item class for a archive table row by ar_rev_id -- actually
367 * used via RevDel_RevisionList.
368 */
369 class RevDel_ArchivedRevisionItem extends RevDel_ArchiveItem {
370 public function __construct( $list, $row ) {
371 RevDel_Item::__construct( $list, $row );
372
373 $this->revision = Revision::newFromArchiveRow( $row,
374 array( 'page' => $this->list->title->getArticleId() ) );
375 }
376
377 public function getIdField() {
378 return 'ar_rev_id';
379 }
380
381 public function getId() {
382 return $this->revision->getId();
383 }
384
385 public function setBits( $bits ) {
386 $dbw = wfGetDB( DB_MASTER );
387 $dbw->update( 'archive',
388 array( 'ar_deleted' => $bits ),
389 array( 'ar_rev_id' => $this->row->ar_rev_id,
390 'ar_deleted' => $this->getBits()
391 ),
392 __METHOD__ );
393 return (bool)$dbw->affectedRows();
394 }
395 }
396
397 /**
398 * List for oldimage table items
399 */
400 class RevDel_FileList extends RevDel_List {
401 public function getType() {
402 return 'oldimage';
403 }
404
405 public static function getRelationType() {
406 return 'oi_archive_name';
407 }
408
409 var $storeBatch, $deleteBatch, $cleanupBatch;
410
411 /**
412 * @param $db DatabaseBase
413 * @return mixed
414 */
415 public function doQuery( $db ) {
416 $archiveNames = array();
417 foreach( $this->ids as $timestamp ) {
418 $archiveNames[] = $timestamp . '!' . $this->title->getDBkey();
419 }
420 return $db->select( 'oldimage', '*',
421 array(
422 'oi_name' => $this->title->getDBkey(),
423 'oi_archive_name' => $archiveNames
424 ),
425 __METHOD__,
426 array( 'ORDER BY' => 'oi_timestamp DESC' )
427 );
428 }
429
430 public function newItem( $row ) {
431 return new RevDel_FileItem( $this, $row );
432 }
433
434 public function clearFileOps() {
435 $this->deleteBatch = array();
436 $this->storeBatch = array();
437 $this->cleanupBatch = array();
438 }
439
440 public function doPreCommitUpdates() {
441 $status = Status::newGood();
442 $repo = RepoGroup::singleton()->getLocalRepo();
443 if ( $this->storeBatch ) {
444 $status->merge( $repo->storeBatch( $this->storeBatch, FileRepo::OVERWRITE_SAME ) );
445 }
446 if ( !$status->isOK() ) {
447 return $status;
448 }
449 if ( $this->deleteBatch ) {
450 $status->merge( $repo->deleteBatch( $this->deleteBatch ) );
451 }
452 if ( !$status->isOK() ) {
453 // Running cleanupDeletedBatch() after a failed storeBatch() with the DB already
454 // modified (but destined for rollback) causes data loss
455 return $status;
456 }
457 if ( $this->cleanupBatch ) {
458 $status->merge( $repo->cleanupDeletedBatch( $this->cleanupBatch ) );
459 }
460 return $status;
461 }
462
463 public function doPostCommitUpdates() {
464 $file = wfLocalFile( $this->title );
465 $file->purgeCache();
466 $file->purgeDescription();
467 return Status::newGood();
468 }
469
470 public function getSuppressBit() {
471 return File::DELETED_RESTRICTED;
472 }
473 }
474
475 /**
476 * Item class for an oldimage table row
477 */
478 class RevDel_FileItem extends RevDel_Item {
479
480 /**
481 * @var File
482 */
483 var $file;
484
485 public function __construct( $list, $row ) {
486 parent::__construct( $list, $row );
487 $this->file = RepoGroup::singleton()->getLocalRepo()->newFileFromRow( $row );
488 }
489
490 public function getIdField() {
491 return 'oi_archive_name';
492 }
493
494 public function getTimestampField() {
495 return 'oi_timestamp';
496 }
497
498 public function getAuthorIdField() {
499 return 'oi_user';
500 }
501
502 public function getAuthorNameField() {
503 return 'oi_user_text';
504 }
505
506 public function getId() {
507 $parts = explode( '!', $this->row->oi_archive_name );
508 return $parts[0];
509 }
510
511 public function canView() {
512 return $this->file->userCan( File::DELETED_RESTRICTED );
513 }
514
515 public function canViewContent() {
516 return $this->file->userCan( File::DELETED_FILE );
517 }
518
519 public function getBits() {
520 return $this->file->getVisibility();
521 }
522
523 public function setBits( $bits ) {
524 # Queue the file op
525 # @todo FIXME: Move to LocalFile.php
526 if ( $this->isDeleted() ) {
527 if ( $bits & File::DELETED_FILE ) {
528 # Still deleted
529 } else {
530 # Newly undeleted
531 $key = $this->file->getStorageKey();
532 $srcRel = $this->file->repo->getDeletedHashPath( $key ) . $key;
533 $this->list->storeBatch[] = array(
534 $this->file->repo->getVirtualUrl( 'deleted' ) . '/' . $srcRel,
535 'public',
536 $this->file->getRel()
537 );
538 $this->list->cleanupBatch[] = $key;
539 }
540 } elseif ( $bits & File::DELETED_FILE ) {
541 # Newly deleted
542 $key = $this->file->getStorageKey();
543 $dstRel = $this->file->repo->getDeletedHashPath( $key ) . $key;
544 $this->list->deleteBatch[] = array( $this->file->getRel(), $dstRel );
545 }
546
547 # Do the database operations
548 $dbw = wfGetDB( DB_MASTER );
549 $dbw->update( 'oldimage',
550 array( 'oi_deleted' => $bits ),
551 array(
552 'oi_name' => $this->row->oi_name,
553 'oi_timestamp' => $this->row->oi_timestamp,
554 'oi_deleted' => $this->getBits()
555 ),
556 __METHOD__
557 );
558 return (bool)$dbw->affectedRows();
559 }
560
561 public function isDeleted() {
562 return $this->file->isDeleted( File::DELETED_FILE );
563 }
564
565 /**
566 * Get the link to the file.
567 * Overridden by RevDel_ArchivedFileItem.
568 */
569 protected function getLink() {
570 $date = $this->list->getLang()->timeanddate( $this->file->getTimestamp(), true );
571 if ( $this->isDeleted() ) {
572 # Hidden files...
573 if ( !$this->canViewContent() ) {
574 $link = $date;
575 } else {
576 $revdelete = SpecialPage::getTitleFor( 'Revisiondelete' );
577 $link = Linker::link(
578 $revdelete,
579 $date, array(),
580 array(
581 'target' => $this->list->title->getPrefixedText(),
582 'file' => $this->file->getArchiveName(),
583 'token' => $this->list->getUser()->editToken(
584 $this->file->getArchiveName() )
585 )
586 );
587 }
588 return '<span class="history-deleted">' . $link . '</span>';
589 } else {
590 # Regular files...
591 return Xml::element( 'a', array( 'href' => $this->file->getUrl() ), $date );
592 }
593 }
594 /**
595 * Generate a user tool link cluster if the current user is allowed to view it
596 * @return string HTML
597 */
598 protected function getUserTools() {
599 if( $this->file->userCan( Revision::DELETED_USER ) ) {
600 $link = Linker::userLink( $this->file->user, $this->file->user_text ) .
601 Linker::userToolLinks( $this->file->user, $this->file->user_text );
602 } else {
603 $link = wfMsgHtml( 'rev-deleted-user' );
604 }
605 if( $this->file->isDeleted( Revision::DELETED_USER ) ) {
606 return '<span class="history-deleted">' . $link . '</span>';
607 }
608 return $link;
609 }
610
611 /**
612 * Wrap and format the file's comment block, if the current
613 * user is allowed to view it.
614 *
615 * @return string HTML
616 */
617 protected function getComment() {
618 if( $this->file->userCan( File::DELETED_COMMENT ) ) {
619 $block = Linker::commentBlock( $this->file->description );
620 } else {
621 $block = ' ' . wfMsgHtml( 'rev-deleted-comment' );
622 }
623 if( $this->file->isDeleted( File::DELETED_COMMENT ) ) {
624 return "<span class=\"history-deleted\">$block</span>";
625 }
626 return $block;
627 }
628
629 public function getHTML() {
630 $data =
631 wfMsg(
632 'widthheight',
633 $this->list->getLang()->formatNum( $this->file->getWidth() ),
634 $this->list->getLang()->formatNum( $this->file->getHeight() )
635 ) .
636 ' (' .
637 wfMsgExt( 'nbytes', 'parsemag', $this->list->getLang()->formatNum( $this->file->getSize() ) ) .
638 ')';
639
640 return '<li>' . $this->getLink() . ' ' . $this->getUserTools() . ' ' .
641 $data . ' ' . $this->getComment(). '</li>';
642 }
643 }
644
645 /**
646 * List for filearchive table items
647 */
648 class RevDel_ArchivedFileList extends RevDel_FileList {
649 public function getType() {
650 return 'filearchive';
651 }
652
653 public static function getRelationType() {
654 return 'fa_id';
655 }
656
657 /**
658 * @param $db DatabaseBase
659 * @return mixed
660 */
661 public function doQuery( $db ) {
662 $ids = array_map( 'intval', $this->ids );
663 return $db->select( 'filearchive', '*',
664 array(
665 'fa_name' => $this->title->getDBkey(),
666 'fa_id' => $ids
667 ),
668 __METHOD__,
669 array( 'ORDER BY' => 'fa_id DESC' )
670 );
671 }
672
673 public function newItem( $row ) {
674 return new RevDel_ArchivedFileItem( $this, $row );
675 }
676 }
677
678 /**
679 * Item class for a filearchive table row
680 */
681 class RevDel_ArchivedFileItem extends RevDel_FileItem {
682 public function __construct( $list, $row ) {
683 RevDel_Item::__construct( $list, $row );
684 $this->file = ArchivedFile::newFromRow( $row );
685 }
686
687 public function getIdField() {
688 return 'fa_id';
689 }
690
691 public function getTimestampField() {
692 return 'fa_timestamp';
693 }
694
695 public function getAuthorIdField() {
696 return 'fa_user';
697 }
698
699 public function getAuthorNameField() {
700 return 'fa_user_text';
701 }
702
703 public function getId() {
704 return $this->row->fa_id;
705 }
706
707 public function setBits( $bits ) {
708 $dbw = wfGetDB( DB_MASTER );
709 $dbw->update( 'filearchive',
710 array( 'fa_deleted' => $bits ),
711 array(
712 'fa_id' => $this->row->fa_id,
713 'fa_deleted' => $this->getBits(),
714 ),
715 __METHOD__
716 );
717 return (bool)$dbw->affectedRows();
718 }
719
720 protected function getLink() {
721 $date = $this->list->getLang()->timeanddate( $this->file->getTimestamp(), true );
722 $undelete = SpecialPage::getTitleFor( 'Undelete' );
723 $key = $this->file->getKey();
724 # Hidden files...
725 if( !$this->canViewContent() ) {
726 $link = $date;
727 } else {
728 $link = Linker::link( $undelete, $date, array(),
729 array(
730 'target' => $this->list->title->getPrefixedText(),
731 'file' => $key,
732 'token' => $this->list->getUser()->editToken( $key )
733 )
734 );
735 }
736 if( $this->isDeleted() ) {
737 $link = '<span class="history-deleted">' . $link . '</span>';
738 }
739 return $link;
740 }
741 }
742
743 /**
744 * List for logging table items
745 */
746 class RevDel_LogList extends RevDel_List {
747 public function getType() {
748 return 'logging';
749 }
750
751 public static function getRelationType() {
752 return 'log_id';
753 }
754
755 /**
756 * @param $db DatabaseBase
757 * @return mixed
758 */
759 public function doQuery( $db ) {
760 $ids = array_map( 'intval', $this->ids );
761 return $db->select( 'logging', '*',
762 array( 'log_id' => $ids ),
763 __METHOD__,
764 array( 'ORDER BY' => 'log_id DESC' )
765 );
766 }
767
768 public function newItem( $row ) {
769 return new RevDel_LogItem( $this, $row );
770 }
771
772 public function getSuppressBit() {
773 return Revision::DELETED_RESTRICTED;
774 }
775
776 public function getLogAction() {
777 return 'event';
778 }
779
780 public function getLogParams( $params ) {
781 return array(
782 implode( ',', $params['ids'] ),
783 "ofield={$params['oldBits']}",
784 "nfield={$params['newBits']}"
785 );
786 }
787 }
788
789 /**
790 * Item class for a logging table row
791 */
792 class RevDel_LogItem extends RevDel_Item {
793 public function getIdField() {
794 return 'log_id';
795 }
796
797 public function getTimestampField() {
798 return 'log_timestamp';
799 }
800
801 public function getAuthorIdField() {
802 return 'log_user';
803 }
804
805 public function getAuthorNameField() {
806 return 'log_user_text';
807 }
808
809 public function canView() {
810 return LogEventsList::userCan( $this->row, Revision::DELETED_RESTRICTED );
811 }
812
813 public function canViewContent() {
814 return true; // none
815 }
816
817 public function getBits() {
818 return $this->row->log_deleted;
819 }
820
821 public function setBits( $bits ) {
822 $dbw = wfGetDB( DB_MASTER );
823 $dbw->update( 'recentchanges',
824 array(
825 'rc_deleted' => $bits,
826 'rc_patrolled' => 1
827 ),
828 array(
829 'rc_logid' => $this->row->log_id,
830 'rc_timestamp' => $this->row->log_timestamp // index
831 ),
832 __METHOD__
833 );
834 $dbw->update( 'logging',
835 array( 'log_deleted' => $bits ),
836 array(
837 'log_id' => $this->row->log_id,
838 'log_deleted' => $this->getBits()
839 ),
840 __METHOD__
841 );
842 return (bool)$dbw->affectedRows();
843 }
844
845 public function getHTML() {
846 $date = htmlspecialchars( $this->list->getLang()->timeanddate( $this->row->log_timestamp ) );
847 $paramArray = LogPage::extractParams( $this->row->log_params );
848 $title = Title::makeTitle( $this->row->log_namespace, $this->row->log_title );
849
850 // Log link for this page
851 $loglink = Linker::link(
852 SpecialPage::getTitleFor( 'Log' ),
853 wfMsgHtml( 'log' ),
854 array(),
855 array( 'page' => $title->getPrefixedText() )
856 );
857 // Action text
858 if( !$this->canView() ) {
859 $action = '<span class="history-deleted">' . wfMsgHtml('rev-deleted-event') . '</span>';
860 } else {
861 $skin = $this->list->getUser()->getSkin();
862 $action = LogPage::actionText( $this->row->log_type, $this->row->log_action,
863 $title, $skin, $paramArray, true, true );
864 if( $this->row->log_deleted & LogPage::DELETED_ACTION )
865 $action = '<span class="history-deleted">' . $action . '</span>';
866 }
867 // User links
868 $userLink = Linker::userLink( $this->row->log_user,
869 User::WhoIs( $this->row->log_user ) );
870 if( LogEventsList::isDeleted($this->row,LogPage::DELETED_USER) ) {
871 $userLink = '<span class="history-deleted">' . $userLink . '</span>';
872 }
873 // Comment
874 $comment = $this->list->getLang()->getDirMark() . Linker::commentBlock( $this->row->log_comment );
875 if( LogEventsList::isDeleted($this->row,LogPage::DELETED_COMMENT) ) {
876 $comment = '<span class="history-deleted">' . $comment . '</span>';
877 }
878 return "<li>($loglink) $date $userLink $action $comment</li>";
879 }
880 }