~vcs-imports/stellarium-website/trunk

« back to all changes in this revision

Viewing changes to wiki/includes/LogEventsList.php

  • Committer: Matthew Gates
  • Date: 2010-12-24 21:26:07 UTC
  • Revision ID: matthewg42@gmail.com-20101224212607-rjlt7qam0160puxb
added wiki directory but without LocalSettings.php; added util directory w/ 2 scripts

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
# Copyright (C) 2004 Brion Vibber <brion@pobox.com>, 2008 Aaron Schulz
 
3
# http://www.mediawiki.org/
 
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
class LogEventsList {
 
21
        const NO_ACTION_LINK = 1;
 
22
 
 
23
        private $skin;
 
24
        private $out;
 
25
        public $flags;
 
26
 
 
27
        public function __construct( $skin, $out, $flags = 0 ) {
 
28
                $this->skin = $skin;
 
29
                $this->out = $out;
 
30
                $this->flags = $flags;
 
31
                $this->preCacheMessages();
 
32
        }
 
33
 
 
34
        /**
 
35
         * As we use the same small set of messages in various methods and that
 
36
         * they are called often, we call them once and save them in $this->message
 
37
         */
 
38
        private function preCacheMessages() {
 
39
                // Precache various messages
 
40
                if( !isset( $this->message ) ) {
 
41
                        $messages = array( 'revertmerge', 'protect_change', 'unblocklink', 'change-blocklink',
 
42
                                'revertmove', 'undeletelink', 'undeleteviewlink', 'revdel-restore', 'hist', 'diff',
 
43
                                'pipe-separator' );
 
44
                        foreach( $messages as $msg ) {
 
45
                                $this->message[$msg] = wfMsgExt( $msg, array( 'escapenoentities' ) );
 
46
                        }
 
47
                }
 
48
        }
 
49
 
 
50
        /**
 
51
         * Set page title and show header for this log type
 
52
         * @param $type Array
 
53
         */
 
54
        public function showHeader( $type ) {
 
55
                // If only one log type is used, then show a special message...
 
56
                $headerType = (count($type) == 1) ? $type[0] : '';
 
57
                if( LogPage::isLogType( $headerType ) ) {
 
58
                        $this->out->setPageTitle( LogPage::logName( $headerType ) );
 
59
                        $this->out->addHTML( LogPage::logHeader( $headerType ) );
 
60
                } else {
 
61
                        $this->out->addHTML( wfMsgExt('alllogstext',array('parseinline')) );
 
62
                }
 
63
        }
 
64
 
 
65
        /**
 
66
         * Show options for the log list
 
67
         * @param $types string or Array
 
68
         * @param $user String
 
69
         * @param $page String
 
70
         * @param $pattern String
 
71
         * @param $year Integer: year
 
72
         * @param $month Integer: month
 
73
         * @param $filter: array
 
74
         * @param $tagFilter: array?
 
75
         */
 
76
        public function showOptions( $types=array(), $user='', $page='', $pattern='', $year='', 
 
77
                $month = '', $filter = null, $tagFilter='' )
 
78
        {
 
79
                global $wgScript, $wgMiserMode;
 
80
 
 
81
                $action = $wgScript;
 
82
                $title = SpecialPage::getTitleFor( 'Log' );
 
83
                $special = $title->getPrefixedDBkey();
 
84
 
 
85
                // For B/C, we take strings, but make sure they are converted...
 
86
                $types = ($types === '') ? array() : (array)$types;
 
87
 
 
88
                $tagSelector = ChangeTags::buildTagFilterSelector( $tagFilter );
 
89
 
 
90
                $html = '';
 
91
                $html .= Xml::hidden( 'title', $special );
 
92
 
 
93
                // Basic selectors
 
94
                $html .= $this->getTypeMenu( $types ) . "\n";
 
95
                $html .= $this->getUserInput( $user ) . "\n";
 
96
                $html .= $this->getTitleInput( $page ) . "\n";
 
97
                $html .= $this->getExtraInputs( $types ) . "\n";
 
98
 
 
99
                // Title pattern, if allowed
 
100
                if (!$wgMiserMode) {
 
101
                        $html .= $this->getTitlePattern( $pattern ) . "\n";
 
102
                }
 
103
 
 
104
                // date menu
 
105
                $html .= Xml::tags( 'p', null, Xml::dateMenu( $year, $month ) );
 
106
 
 
107
                // Tag filter
 
108
                if ($tagSelector) {
 
109
                        $html .= Xml::tags( 'p', null, implode( '&nbsp;', $tagSelector ) );
 
110
                }
 
111
 
 
112
                // Filter links
 
113
                if ($filter) {
 
114
                        $html .= Xml::tags( 'p', null, $this->getFilterLinks( $filter ) );
 
115
                }
 
116
 
 
117
                // Submit button
 
118
                $html .= Xml::submitButton( wfMsg( 'allpagessubmit' ) );
 
119
 
 
120
                // Fieldset
 
121
                $html = Xml::fieldset( wfMsg( 'log' ), $html );
 
122
 
 
123
                // Form wrapping
 
124
                $html = Xml::tags( 'form', array( 'action' => $action, 'method' => 'get' ), $html );
 
125
 
 
126
                $this->out->addHTML( $html );
 
127
        }
 
128
 
 
129
        /**
 
130
         * @param $filter Array
 
131
         * @return String: Formatted HTML
 
132
         */
 
133
        private function getFilterLinks( $filter ) {
 
134
                global $wgTitle, $wgLang;
 
135
                // show/hide links
 
136
                $messages = array( wfMsgHtml( 'show' ), wfMsgHtml( 'hide' ) );
 
137
                // Option value -> message mapping
 
138
                $links = array();
 
139
                $hiddens = ''; // keep track for "go" button
 
140
                foreach( $filter as $type => $val ) {
 
141
                        // Should the below assignment be outside the foreach?
 
142
                        // Then it would have to be copied. Not certain what is more expensive.
 
143
                        $query = $this->getDefaultQuery();
 
144
                        $queryKey = "hide_{$type}_log";
 
145
 
 
146
                        $hideVal = 1 - intval($val);
 
147
                        $query[$queryKey] = $hideVal;
 
148
 
 
149
                        $link = $this->skin->link(
 
150
                                $wgTitle,
 
151
                                $messages[$hideVal],
 
152
                                array(),
 
153
                                $query,
 
154
                                array( 'known', 'noclasses' )
 
155
                        );
 
156
 
 
157
                        $links[$type] = wfMsgHtml( "log-show-hide-{$type}", $link );
 
158
                        $hiddens .= Xml::hidden( "hide_{$type}_log", $val ) . "\n";
 
159
                }
 
160
                // Build links
 
161
                return '<small>'.$wgLang->pipeList( $links ) . '</small>' . $hiddens;
 
162
        }
 
163
 
 
164
        private function getDefaultQuery() {
 
165
                if ( !isset( $this->mDefaultQuery ) ) {
 
166
                        $this->mDefaultQuery = $_GET;
 
167
                        unset( $this->mDefaultQuery['title'] );
 
168
                        unset( $this->mDefaultQuery['dir'] );
 
169
                        unset( $this->mDefaultQuery['offset'] );
 
170
                        unset( $this->mDefaultQuery['limit'] );
 
171
                        unset( $this->mDefaultQuery['order'] );
 
172
                        unset( $this->mDefaultQuery['month'] );
 
173
                        unset( $this->mDefaultQuery['year'] );
 
174
                }
 
175
                return $this->mDefaultQuery;
 
176
        }
 
177
 
 
178
        /**
 
179
         * @param $queryTypes Array
 
180
         * @return String: Formatted HTML
 
181
         */
 
182
        private function getTypeMenu( $queryTypes ) {
 
183
                global $wgLogRestrictions, $wgUser;
 
184
 
 
185
                $html = "<select name='type'>\n";
 
186
 
 
187
                $validTypes = LogPage::validTypes();
 
188
                $typesByName = array(); // Temporary array
 
189
 
 
190
                // First pass to load the log names
 
191
                foreach( $validTypes as $type ) {
 
192
                        $text = LogPage::logName( $type );
 
193
                        $typesByName[$type] = $text;
 
194
                }
 
195
 
 
196
                // Second pass to sort by name
 
197
                asort($typesByName);
 
198
 
 
199
                // Note the query type
 
200
                $queryType = count($queryTypes) == 1 ? $queryTypes[0] : '';
 
201
                // Third pass generates sorted XHTML content
 
202
                foreach( $typesByName as $type => $text ) {
 
203
                        $selected = ($type == $queryType);
 
204
                        // Restricted types
 
205
                        if ( isset($wgLogRestrictions[$type]) ) {
 
206
                                if ( $wgUser->isAllowed( $wgLogRestrictions[$type] ) ) {
 
207
                                        $html .= Xml::option( $text, $type, $selected ) . "\n";
 
208
                                }
 
209
                        } else {
 
210
                                $html .= Xml::option( $text, $type, $selected ) . "\n";
 
211
                        }
 
212
                }
 
213
 
 
214
                $html .= '</select>';
 
215
                return $html;
 
216
        }
 
217
 
 
218
        /**
 
219
         * @param $user String
 
220
         * @return String: Formatted HTML
 
221
         */
 
222
        private function getUserInput( $user ) {
 
223
                return '<span style="white-space: nowrap">' .
 
224
                        Xml::inputLabel( wfMsg( 'specialloguserlabel' ), 'user', 'mw-log-user', 15, $user ) .
 
225
                        '</span>';
 
226
        }
 
227
 
 
228
        /**
 
229
         * @param $title String
 
230
         * @return String: Formatted HTML
 
231
         */
 
232
        private function getTitleInput( $title ) {
 
233
                return '<span style="white-space: nowrap">' .
 
234
                        Xml::inputLabel( wfMsg( 'speciallogtitlelabel' ), 'page', 'mw-log-page', 20, $title ) .
 
235
                        '</span>';
 
236
        }
 
237
 
 
238
        /**
 
239
         * @return boolean Checkbox
 
240
         */
 
241
        private function getTitlePattern( $pattern ) {
 
242
                return '<span style="white-space: nowrap">' .
 
243
                        Xml::checkLabel( wfMsg( 'log-title-wildcard' ), 'pattern', 'pattern', $pattern ) .
 
244
                        '</span>';
 
245
        }
 
246
 
 
247
        private function getExtraInputs( $types ) {
 
248
                global $wgRequest;
 
249
                $offender = $wgRequest->getVal('offender');
 
250
                $user = User::newFromName( $offender, false );
 
251
                if( !$user || ($user->getId() == 0 && !IP::isIPAddress($offender) ) ) {
 
252
                        $offender = ''; // Blank field if invalid
 
253
                }
 
254
                if( count($types) == 1 && $types[0] == 'suppress' ) {
 
255
                        return Xml::inputLabel( wfMsg('revdelete-offender'), 'offender',
 
256
                                'mw-log-offender', 20, $offender );
 
257
                }
 
258
                return '';
 
259
        }
 
260
 
 
261
        public function beginLogEventsList() {
 
262
                return "<ul>\n";
 
263
        }
 
264
 
 
265
        public function endLogEventsList() {
 
266
                return "</ul>\n";
 
267
        }
 
268
 
 
269
        /**
 
270
         * @param $row Row: a single row from the result set
 
271
         * @return String: Formatted HTML list item
 
272
         */
 
273
        public function logLine( $row ) {
 
274
                global $wgLang, $wgUser, $wgContLang;
 
275
 
 
276
                $title = Title::makeTitle( $row->log_namespace, $row->log_title );
 
277
                $classes = array( "mw-logline-{$row->log_type}" );
 
278
                $time = $wgLang->timeanddate( wfTimestamp( TS_MW, $row->log_timestamp ), true );
 
279
                // User links
 
280
                if( self::isDeleted( $row, LogPage::DELETED_USER ) ) {
 
281
                        $userLink = '<span class="history-deleted">' . wfMsgHtml( 'rev-deleted-user' ) . '</span>';
 
282
                } else {
 
283
                        $userLink = $this->skin->userLink( $row->log_user, $row->user_name ) .
 
284
                                $this->skin->userToolLinks( $row->log_user, $row->user_name, true, 0, $row->user_editcount );
 
285
                }
 
286
                // Comment
 
287
                if( self::isDeleted( $row, LogPage::DELETED_COMMENT ) ) {
 
288
                        $comment = '<span class="history-deleted">' . wfMsgHtml( 'rev-deleted-comment' ) . '</span>';
 
289
                } else {
 
290
                        $comment = $wgContLang->getDirMark() . $this->skin->commentBlock( $row->log_comment );
 
291
                }
 
292
                // Extract extra parameters
 
293
                $paramArray = LogPage::extractParams( $row->log_params );
 
294
                $revert = $del = '';
 
295
                // Some user can hide log items and have review links
 
296
                if( !( $this->flags & self::NO_ACTION_LINK ) && $wgUser->isAllowed( 'deletedhistory' ) ) {
 
297
                        // Don't show useless link to people who cannot hide revisions
 
298
                        if( $row->log_deleted || $wgUser->isAllowed( 'deleterevision' ) ) {
 
299
                                $del = $this->getShowHideLinks( $row ) . ' ';
 
300
                        }
 
301
                }
 
302
                // Add review links and such...
 
303
                if( ( $this->flags & self::NO_ACTION_LINK ) || ( $row->log_deleted & LogPage::DELETED_ACTION ) ) {
 
304
                        // Action text is suppressed...
 
305
                } else if( self::typeAction( $row, 'move', 'move', 'move' ) && !empty( $paramArray[0] ) ) {
 
306
                        $destTitle = Title::newFromText( $paramArray[0] );
 
307
                        if( $destTitle ) {
 
308
                                $revert = '(' . $this->skin->link(
 
309
                                        SpecialPage::getTitleFor( 'Movepage' ),
 
310
                                        $this->message['revertmove'],
 
311
                                        array(),
 
312
                                        array(
 
313
                                                'wpOldTitle' => $destTitle->getPrefixedDBkey(),
 
314
                                                'wpNewTitle' => $title->getPrefixedDBkey(),
 
315
                                                'wpReason' => wfMsgForContent( 'revertmove' ),
 
316
                                                'wpMovetalk' => 0
 
317
                                        ),
 
318
                                        array( 'known', 'noclasses' )
 
319
                                ) . ')';
 
320
                        }
 
321
                // Show undelete link
 
322
                } else if( self::typeAction( $row, array( 'delete', 'suppress' ), 'delete', 'deletedhistory' ) ) {
 
323
                        if( !$wgUser->isAllowed( 'undelete' ) ) {
 
324
                                $viewdeleted = $this->message['undeleteviewlink'];
 
325
                        } else {
 
326
                                $viewdeleted = $this->message['undeletelink'];
 
327
                        }
 
328
 
 
329
                        $revert = '(' . $this->skin->link(
 
330
                                SpecialPage::getTitleFor( 'Undelete' ),
 
331
                                $viewdeleted,
 
332
                                array(),
 
333
                                array( 'target' => $title->getPrefixedDBkey() ),
 
334
                                array( 'known', 'noclasses' )
 
335
                         ) . ')';
 
336
                // Show unblock/change block link
 
337
                } else if( self::typeAction( $row, array( 'block', 'suppress' ), array( 'block', 'reblock' ), 'block' ) ) {
 
338
                        $revert = '(' .
 
339
                                $this->skin->link(
 
340
                                        SpecialPage::getTitleFor( 'Ipblocklist' ),
 
341
                                        $this->message['unblocklink'],
 
342
                                        array(),
 
343
                                        array(
 
344
                                                'action' => 'unblock',
 
345
                                                'ip' => $row->log_title
 
346
                                        ),
 
347
                                        'known'
 
348
                                ) .
 
349
                                $this->message['pipe-separator'] .
 
350
                                $this->skin->link(
 
351
                                        SpecialPage::getTitleFor( 'Blockip', $row->log_title ),
 
352
                                        $this->message['change-blocklink'],
 
353
                                        array(),
 
354
                                        array(),
 
355
                                        'known'
 
356
                                ) .
 
357
                                ')';
 
358
                // Show change protection link
 
359
                } else if( self::typeAction( $row, 'protect', array( 'modify', 'protect', 'unprotect' ) ) ) {
 
360
                        $revert .= ' (' .
 
361
                                $this->skin->link( $title,
 
362
                                        $this->message['hist'],
 
363
                                        array(),
 
364
                                        array(
 
365
                                                'action' => 'history',
 
366
                                                'offset' => $row->log_timestamp
 
367
                                        )
 
368
                                );
 
369
                        if( $wgUser->isAllowed( 'protect' ) ) {
 
370
                                $revert .= $this->message['pipe-separator'] .
 
371
                                        $this->skin->link( $title,
 
372
                                                $this->message['protect_change'],
 
373
                                                array(),
 
374
                                                array( 'action' => 'protect' ),
 
375
                                                'known' );
 
376
                        }
 
377
                        $revert .= ')';
 
378
                // Show unmerge link
 
379
                } else if( self::typeAction( $row, 'merge', 'merge', 'mergehistory' ) ) {
 
380
                        $merge = SpecialPage::getTitleFor( 'Mergehistory' );
 
381
                        $revert = '(' . $this->skin->link(
 
382
                                $merge,
 
383
                                $this->message['revertmerge'],
 
384
                                array(),
 
385
                                array(
 
386
                                        'target' => $paramArray[0],
 
387
                                        'dest' => $title->getPrefixedDBkey(),
 
388
                                        'mergepoint' => $paramArray[1]
 
389
                                ),
 
390
                                array( 'known', 'noclasses' )
 
391
                        ) . ')';
 
392
                // If an edit was hidden from a page give a review link to the history
 
393
                } else if( self::typeAction( $row, array( 'delete', 'suppress' ), 'revision', 'deletedhistory' ) ) {
 
394
                        if( count($paramArray) >= 2 ) {
 
395
                                // Different revision types use different URL params...
 
396
                                $key = $paramArray[0];
 
397
                                // $paramArray[1] is a CSV of the IDs
 
398
                                $Ids = explode( ',', $paramArray[1] );
 
399
                                $query = $paramArray[1];
 
400
                                $revert = array();
 
401
                                // Diff link for single rev deletions
 
402
                                if( count($Ids) == 1 ) {
 
403
                                        // Live revision diffs...
 
404
                                        if( in_array( $key, array( 'oldid', 'revision' ) ) ) {
 
405
                                                $revert[] = $this->skin->link(
 
406
                                                        $title,
 
407
                                                        $this->message['diff'],
 
408
                                                        array(),
 
409
                                                        array(
 
410
                                                                'diff' => intval( $Ids[0] ),
 
411
                                                                'unhide' => 1
 
412
                                                        ),
 
413
                                                        array( 'known', 'noclasses' )
 
414
                                                );
 
415
                                        // Deleted revision diffs...
 
416
                                        } else if( in_array( $key, array( 'artimestamp','archive' ) ) ) {
 
417
                                                $revert[] = $this->skin->link(
 
418
                                                        SpecialPage::getTitleFor( 'Undelete' ),
 
419
                                                        $this->message['diff'], 
 
420
                                                        array(),
 
421
                                                        array(
 
422
                                                                'target'    => $title->getPrefixedDBKey(),
 
423
                                                                'diff'      => 'prev',
 
424
                                                                'timestamp' => $Ids[0]
 
425
                                                        ),
 
426
                                                        array( 'known', 'noclasses' )
 
427
                                                );
 
428
                                        }
 
429
                                }
 
430
                                // View/modify link...
 
431
                                $revert[] = $this->skin->link(
 
432
                                        SpecialPage::getTitleFor( 'Revisiondelete' ),
 
433
                                        $this->message['revdel-restore'],
 
434
                                        array(),
 
435
                                        array(
 
436
                                                'target' => $title->getPrefixedText(),
 
437
                                                'type' => $key,
 
438
                                                'ids' => $query
 
439
                                        ),
 
440
                                        array( 'known', 'noclasses' )
 
441
                                );
 
442
                                // Pipe links
 
443
                                $revert = wfMsg( 'parentheses', $wgLang->pipeList( $revert ) );
 
444
                        }
 
445
                // Hidden log items, give review link
 
446
                } else if( self::typeAction( $row, array( 'delete', 'suppress' ), 'event', 'deletedhistory' ) ) {
 
447
                        if( count($paramArray) >= 1 ) {
 
448
                                $revdel = SpecialPage::getTitleFor( 'Revisiondelete' );
 
449
                                // $paramArray[1] is a CSV of the IDs
 
450
                                $Ids = explode( ',', $paramArray[0] );
 
451
                                $query = $paramArray[0];
 
452
                                // Link to each hidden object ID, $paramArray[1] is the url param
 
453
                                $revert = '(' . $this->skin->link(
 
454
                                        $revdel,
 
455
                                        $this->message['revdel-restore'], 
 
456
                                        array(),
 
457
                                        array(
 
458
                                                'target' => $title->getPrefixedText(),
 
459
                                                'type' => 'logging',
 
460
                                                'ids' => $query
 
461
                                        ),
 
462
                                        array( 'known', 'noclasses' )
 
463
                                ) . ')';
 
464
                        }
 
465
                // Self-created users
 
466
                } else if( self::typeAction( $row, 'newusers', 'create2' ) ) {
 
467
                        if( isset( $paramArray[0] ) ) {
 
468
                                $revert = $this->skin->userToolLinks( $paramArray[0], $title->getDBkey(), true );
 
469
                        } else {
 
470
                                # Fall back to a blue contributions link
 
471
                                $revert = $this->skin->userToolLinks( 1, $title->getDBkey() );
 
472
                        }
 
473
                        if( $time < '20080129000000' ) {
 
474
                                # Suppress $comment from old entries (before 2008-01-29),
 
475
                                # not needed and can contain incorrect links
 
476
                                $comment = '';
 
477
                        }
 
478
                // Do nothing. The implementation is handled by the hook modifiying the passed-by-ref parameters.
 
479
                } else {
 
480
                        wfRunHooks( 'LogLine', array( $row->log_type, $row->log_action, $title, $paramArray,
 
481
                                &$comment, &$revert, $row->log_timestamp ) );
 
482
                }
 
483
                // Event description
 
484
                if( self::isDeleted( $row, LogPage::DELETED_ACTION ) ) {
 
485
                        $action = '<span class="history-deleted">' . wfMsgHtml( 'rev-deleted-event' ) . '</span>';
 
486
                } else {
 
487
                        $action = LogPage::actionText( $row->log_type, $row->log_action, $title,
 
488
                                $this->skin, $paramArray, true );
 
489
                }
 
490
 
 
491
                // Any tags...
 
492
                list( $tagDisplay, $newClasses ) = ChangeTags::formatSummaryRow( $row->ts_tags, 'logevent' );
 
493
                $classes = array_merge( $classes, $newClasses );
 
494
 
 
495
                if( $revert != '' ) {
 
496
                        $revert = '<span class="mw-logevent-actionlink">' . $revert . '</span>';
 
497
                }
 
498
 
 
499
                $time = htmlspecialchars( $time );
 
500
 
 
501
                return Xml::tags( 'li', array( "class" => implode( ' ', $classes ) ),
 
502
                        $del . $time . ' ' . $userLink . ' ' . $action . ' ' . $comment . ' ' . $revert . " $tagDisplay" ) . "\n";
 
503
        }
 
504
 
 
505
        /**
 
506
         * @param $row Row
 
507
         * @return string
 
508
         */
 
509
        private function getShowHideLinks( $row ) {
 
510
                global $wgUser;
 
511
                if( $row->log_type == 'suppress' ) {
 
512
                        return ''; // No one can hide items from the oversight log
 
513
                }
 
514
                $canHide = $wgUser->isAllowed( 'deleterevision' );
 
515
                // If event was hidden from sysops
 
516
                if( !self::userCan( $row, LogPage::DELETED_RESTRICTED ) ) {
 
517
                        $del = $this->skin->revDeleteLinkDisabled( $canHide );
 
518
                } else {
 
519
                        $target = SpecialPage::getTitleFor( 'Log', $row->log_type );
 
520
                        $page = Title::makeTitle( $row->log_namespace, $row->log_title );
 
521
                        $query = array(
 
522
                                'target' => $target->getPrefixedDBkey(),
 
523
                                'type'   => 'logging',
 
524
                                'ids'    => $row->log_id,
 
525
                        );
 
526
                        $del = $this->skin->revDeleteLink( $query,
 
527
                                self::isDeleted( $row, LogPage::DELETED_RESTRICTED ), $canHide );
 
528
                }
 
529
                return $del;
 
530
        }
 
531
 
 
532
        /**
 
533
         * @param $row Row
 
534
         * @param $type Mixed: string/array
 
535
         * @param $action Mixed: string/array
 
536
         * @param $right string
 
537
         * @return bool
 
538
         */
 
539
        public static function typeAction( $row, $type, $action, $right='' ) {
 
540
                $match = is_array($type) ?
 
541
                        in_array( $row->log_type, $type ) : $row->log_type == $type;
 
542
                if( $match ) {
 
543
                        $match = is_array( $action ) ?
 
544
                                in_array( $row->log_action, $action ) : $row->log_action == $action;
 
545
                        if( $match && $right ) {
 
546
                                global $wgUser;
 
547
                                $match = $wgUser->isAllowed( $right );
 
548
                        }
 
549
                }
 
550
                return $match;
 
551
        }
 
552
 
 
553
        /**
 
554
         * Determine if the current user is allowed to view a particular
 
555
         * field of this log row, if it's marked as deleted.
 
556
         * @param $row Row
 
557
         * @param $field Integer
 
558
         * @return Boolean
 
559
         */
 
560
        public static function userCan( $row, $field ) {
 
561
                return self::userCanBitfield( $row->log_deleted, $field );
 
562
        }
 
563
        
 
564
        /**
 
565
         * Determine if the current user is allowed to view a particular
 
566
         * field of this log row, if it's marked as deleted.
 
567
         * @param $bitfield Integer (current field)
 
568
         * @param $field Integer
 
569
         * @return Boolean
 
570
         */
 
571
        public static function userCanBitfield( $bitfield, $field ) {
 
572
                if( $bitfield & $field ) {
 
573
                        global $wgUser;
 
574
                        $permission = '';
 
575
                        if ( $bitfield & LogPage::DELETED_RESTRICTED ) {
 
576
                                $permission = 'suppressrevision';
 
577
                        } else {
 
578
                                $permission = 'deletedhistory';
 
579
                        }
 
580
                        wfDebug( "Checking for $permission due to $field match on $bitfield\n" );
 
581
                        return $wgUser->isAllowed( $permission );
 
582
                } else {
 
583
                        return true;
 
584
                }
 
585
        }
 
586
 
 
587
        /**
 
588
         * @param $row Row
 
589
         * @param $field Integer: one of DELETED_* bitfield constants
 
590
         * @return Boolean
 
591
         */
 
592
        public static function isDeleted( $row, $field ) {
 
593
                return ( $row->log_deleted & $field ) == $field;
 
594
        }
 
595
 
 
596
        /**
 
597
         * Show log extract. Either with text and a box (set $msgKey) or without (don't set $msgKey)
 
598
         * @param $out OutputPage or String-by-reference
 
599
         * @param $types String or Array
 
600
         * @param $page String The page title to show log entries for
 
601
         * @param $user String The user who made the log entries
 
602
         * @param $param Associative Array with the following additional options:
 
603
         * - lim Integer Limit of items to show, default is 50
 
604
         * - conds Array Extra conditions for the query (e.g. "log_action != 'revision'")
 
605
         * - showIfEmpty boolean Set to false if you don't want any output in case the loglist is empty
 
606
         *   if set to true (default), "No matching items in log" is displayed if loglist is empty
 
607
         * - msgKey Array If you want a nice box with a message, set this to the key of the message.
 
608
         *   First element is the message key, additional optional elements are parameters for the key
 
609
         *   that are processed with wgMsgExt and option 'parse'
 
610
         * - offset Set to overwrite offset parameter in $wgRequest
 
611
         *   set to '' to unset offset
 
612
         * - wrap String: Wrap the message in html (usually something like "<div ...>$1</div>").
 
613
         * @return Integer Number of total log items (not limited by $lim)
 
614
         */
 
615
        public static function showLogExtract( &$out, $types=array(), $page='', $user='', 
 
616
                        $param = array() ) {
 
617
 
 
618
                $defaultParameters = array(
 
619
                        'lim' => 25,
 
620
                        'conds' => array(),
 
621
                        'showIfEmpty' => true,
 
622
                        'msgKey' => array(''),
 
623
                        'wrap' => "$1"
 
624
                );
 
625
        
 
626
                # The + operator appends elements of remaining keys from the right
 
627
                # handed array to the left handed, whereas duplicated keys are NOT overwritten.
 
628
                $param += $defaultParameters;
 
629
 
 
630
                global $wgUser, $wgOut;
 
631
                # Convert $param array to individual variables
 
632
                $lim = $param['lim'];
 
633
                $conds = $param['conds'];
 
634
                $showIfEmpty = $param['showIfEmpty'];
 
635
                $msgKey = $param['msgKey'];
 
636
                $wrap = $param['wrap'];
 
637
                if ( !is_array( $msgKey ) )
 
638
                        $msgKey = array( $msgKey );
 
639
                # Insert list of top 50 (or top $lim) items
 
640
                $loglist = new LogEventsList( $wgUser->getSkin(), $wgOut, 0 );
 
641
                $pager = new LogPager( $loglist, $types, $user, $page, '', $conds );
 
642
                if ( isset( $param['offset'] ) ) # Tell pager to ignore $wgRequest offset
 
643
                        $pager->setOffset( $param['offset'] );
 
644
                if( $lim > 0 ) $pager->mLimit = $lim;
 
645
                $logBody = $pager->getBody();
 
646
                $s = '';
 
647
                if( $logBody ) {
 
648
                        if ( $msgKey[0] ) {
 
649
                                $s = '<div class="mw-warning-with-logexcerpt">';
 
650
 
 
651
                                if ( count( $msgKey ) == 1 ) {
 
652
                                        $s .= wfMsgExt( $msgKey[0], array( 'parse' ) );
 
653
                                } else { // Process additional arguments
 
654
                                        $args = $msgKey;
 
655
                                        array_shift( $args );
 
656
                                        $s .= wfMsgExt( $msgKey[0], array( 'parse' ), $args );
 
657
                                }
 
658
                        }
 
659
                        $s .= $loglist->beginLogEventsList() .
 
660
                                 $logBody .
 
661
                                 $loglist->endLogEventsList();
 
662
                } else {
 
663
                        if ( $showIfEmpty )
 
664
                                $s = Html::rawElement( 'div', array( 'class' => 'mw-warning-logempty' ),
 
665
                                        wfMsgExt( 'logempty', array( 'parseinline' ) ) );
 
666
                }
 
667
                if( $pager->getNumRows() > $pager->mLimit ) { # Show "Full log" link
 
668
                        $urlParam = array();
 
669
                        if ( $page != '')
 
670
                                $urlParam['page'] = $page;
 
671
                        if ( $user != '')
 
672
                                $urlParam['user'] = $user;
 
673
                        if ( !is_array( $types ) ) # Make it an array, if it isn't
 
674
                                $types = array( $types );
 
675
                        # If there is exactly one log type, we can link to Special:Log?type=foo
 
676
                        if ( count( $types ) == 1 )
 
677
                                $urlParam['type'] = $types[0];
 
678
                        $s .= $wgUser->getSkin()->link(
 
679
                                SpecialPage::getTitleFor( 'Log' ),
 
680
                                wfMsgHtml( 'log-fulllog' ),
 
681
                                array(),
 
682
                                $urlParam
 
683
                        );
 
684
 
 
685
                }
 
686
                if ( $logBody && $msgKey[0] )
 
687
                        $s .= '</div>';
 
688
 
 
689
                if ( $wrap!='' ) { // Wrap message in html
 
690
                        $s = str_replace( '$1', $s, $wrap );
 
691
                }
 
692
 
 
693
                // $out can be either an OutputPage object or a String-by-reference
 
694
                if( $out instanceof OutputPage ){
 
695
                        $out->addHTML( $s );
 
696
                } else {
 
697
                        $out = $s;
 
698
                }
 
699
                return $pager->getNumRows();
 
700
        }
 
701
 
 
702
        /**
 
703
         * SQL clause to skip forbidden log types for this user
 
704
         * @param $db Database
 
705
         * @param $audience string, public/user
 
706
         * @return mixed (string or false)
 
707
         */
 
708
        public static function getExcludeClause( $db, $audience = 'public' ) {
 
709
                global $wgLogRestrictions, $wgUser;
 
710
                // Reset the array, clears extra "where" clauses when $par is used
 
711
                $hiddenLogs = array();
 
712
                // Don't show private logs to unprivileged users
 
713
                foreach( $wgLogRestrictions as $logType => $right ) {
 
714
                        if( $audience == 'public' || !$wgUser->isAllowed($right) ) {
 
715
                                $safeType = $db->strencode( $logType );
 
716
                                $hiddenLogs[] = $safeType;
 
717
                        }
 
718
                }
 
719
                if( count($hiddenLogs) == 1 ) {
 
720
                        return 'log_type != ' . $db->addQuotes( $hiddenLogs[0] );
 
721
                } elseif( $hiddenLogs ) {
 
722
                        return 'log_type NOT IN (' . $db->makeList($hiddenLogs) . ')';
 
723
                }
 
724
                return false;
 
725
        }
 
726
}
 
727
 
 
728
/**
 
729
 * @ingroup Pager
 
730
 */
 
731
class LogPager extends ReverseChronologicalPager {
 
732
        private $types = array(), $user = '', $title = '', $pattern = '';
 
733
        private $typeCGI = '';
 
734
        public $mLogEventsList;
 
735
 
 
736
        /**
 
737
         * constructor
 
738
         * @param $list LogEventsList
 
739
         * @param $types String or Array log types to show
 
740
         * @param $user String The user who made the log entries
 
741
         * @param $title String The page title the log entries are for
 
742
         * @param $pattern String Do a prefix search rather than an exact title match
 
743
         * @param $conds Array Extra conditions for the query
 
744
         * @param $year Integer The year to start from
 
745
         * @param $month Integer The month to start from
 
746
         */
 
747
        public function __construct( $list, $types = array(), $user = '', $title = '', $pattern = '',
 
748
                $conds = array(), $year = false, $month = false, $tagFilter = '' ) 
 
749
        {
 
750
                parent::__construct();
 
751
                $this->mConds = $conds;
 
752
 
 
753
                $this->mLogEventsList = $list;
 
754
 
 
755
                $this->limitType( $types ); // also excludes hidden types
 
756
                $this->limitUser( $user );
 
757
                $this->limitTitle( $title, $pattern );
 
758
                $this->getDateCond( $year, $month );
 
759
                $this->mTagFilter = $tagFilter;
 
760
        }
 
761
 
 
762
        public function getDefaultQuery() {
 
763
                $query = parent::getDefaultQuery();
 
764
                $query['type'] = $this->typeCGI; // arrays won't work here
 
765
                $query['user'] = $this->user;
 
766
                $query['month'] = $this->mMonth;
 
767
                $query['year'] = $this->mYear;
 
768
                return $query;
 
769
        }
 
770
 
 
771
        // Call ONLY after calling $this->limitType() already!
 
772
        public function getFilterParams() {
 
773
                global $wgFilterLogTypes, $wgUser, $wgRequest;
 
774
                $filters = array();
 
775
                if( count($this->types) ) {
 
776
                        return $filters;
 
777
                }
 
778
                foreach( $wgFilterLogTypes as $type => $default ) {
 
779
                        // Avoid silly filtering
 
780
                        if( $type !== 'patrol' || $wgUser->useNPPatrol() ) {
 
781
                                $hide = $wgRequest->getInt( "hide_{$type}_log", $default );
 
782
                                $filters[$type] = $hide;
 
783
                                if( $hide )
 
784
                                        $this->mConds[] = 'log_type != ' . $this->mDb->addQuotes( $type );
 
785
                        }
 
786
                }
 
787
                return $filters;
 
788
        }
 
789
 
 
790
        /**
 
791
         * Set the log reader to return only entries of the given type.
 
792
         * Type restrictions enforced here
 
793
         * @param $types String or array: Log types ('upload', 'delete', etc);
 
794
         *   empty string means no restriction
 
795
         */
 
796
        private function limitType( $types ) {
 
797
                global $wgLogRestrictions, $wgUser;
 
798
                // If $types is not an array, make it an array
 
799
                $types = ($types === '') ? array() : (array)$types;
 
800
                // Don't even show header for private logs; don't recognize it...
 
801
                foreach ( $types as $type ) {
 
802
                        if( isset( $wgLogRestrictions[$type] )
 
803
                                && !$wgUser->isAllowed($wgLogRestrictions[$type])
 
804
                        ) {
 
805
                                $types = array_diff( $types, array( $type ) );
 
806
                        }
 
807
                }
 
808
                $this->types = $types;
 
809
                // Don't show private logs to unprivileged users.
 
810
                // Also, only show them upon specific request to avoid suprises.
 
811
                $audience = $types ? 'user' : 'public';
 
812
                $hideLogs = LogEventsList::getExcludeClause( $this->mDb, $audience );
 
813
                if( $hideLogs !== false ) {
 
814
                        $this->mConds[] = $hideLogs;
 
815
                }
 
816
                if( count($types) ) {
 
817
                        $this->mConds['log_type'] = $types;
 
818
                        // Set typeCGI; used in url param for paging
 
819
                        if( count($types) == 1 ) $this->typeCGI = $types[0];
 
820
                }
 
821
        }
 
822
 
 
823
        /**
 
824
         * Set the log reader to return only entries by the given user.
 
825
         * @param $name String: (In)valid user name
 
826
         */
 
827
        private function limitUser( $name ) {
 
828
                if( $name == '' ) {
 
829
                        return false;
 
830
                }
 
831
                $usertitle = Title::makeTitleSafe( NS_USER, $name );
 
832
                if( is_null($usertitle) ) {
 
833
                        return false;
 
834
                }
 
835
                /* Fetch userid at first, if known, provides awesome query plan afterwards */
 
836
                $userid = User::idFromName( $name );
 
837
                if( !$userid ) {
 
838
                        /* It should be nicer to abort query at all,
 
839
                           but for now it won't pass anywhere behind the optimizer */
 
840
                        $this->mConds[] = "NULL";
 
841
                } else {
 
842
                        global $wgUser;
 
843
                        $this->mConds['log_user'] = $userid;
 
844
                        // Paranoia: avoid brute force searches (bug 17342)
 
845
                        if( !$wgUser->isAllowed( 'deletedhistory' ) ) {
 
846
                                $this->mConds[] = $this->mDb->bitAnd('log_deleted', LogPage::DELETED_USER) . ' = 0';
 
847
                        } else if( !$wgUser->isAllowed( 'suppressrevision' ) ) {
 
848
                                $this->mConds[] = $this->mDb->bitAnd('log_deleted', LogPage::SUPPRESSED_USER) .
 
849
                                        ' != ' . LogPage::SUPPRESSED_USER;
 
850
                        }
 
851
                        $this->user = $usertitle->getText();
 
852
                }
 
853
        }
 
854
 
 
855
        /**
 
856
         * Set the log reader to return only entries affecting the given page.
 
857
         * (For the block and rights logs, this is a user page.)
 
858
         * @param $page String: Title name as text
 
859
         * @param $pattern String
 
860
         */
 
861
        private function limitTitle( $page, $pattern ) {
 
862
                global $wgMiserMode, $wgUser;
 
863
 
 
864
                $title = Title::newFromText( $page );
 
865
                if( strlen( $page ) == 0 || !$title instanceof Title )
 
866
                        return false;
 
867
 
 
868
                $this->title = $title->getPrefixedText();
 
869
                $ns = $title->getNamespace();
 
870
                $db = $this->mDb;
 
871
 
 
872
                # Using the (log_namespace, log_title, log_timestamp) index with a
 
873
                # range scan (LIKE) on the first two parts, instead of simple equality,
 
874
                # makes it unusable for sorting.  Sorted retrieval using another index
 
875
                # would be possible, but then we might have to scan arbitrarily many
 
876
                # nodes of that index. Therefore, we need to avoid this if $wgMiserMode
 
877
                # is on.
 
878
                #
 
879
                # This is not a problem with simple title matches, because then we can
 
880
                # use the page_time index.  That should have no more than a few hundred
 
881
                # log entries for even the busiest pages, so it can be safely scanned
 
882
                # in full to satisfy an impossible condition on user or similar.
 
883
                if( $pattern && !$wgMiserMode ) {
 
884
                        $this->mConds['log_namespace'] = $ns;
 
885
                        $this->mConds[] = 'log_title ' . $db->buildLike( $title->getDBkey(), $db->anyString() );
 
886
                        $this->pattern = $pattern;
 
887
                } else {
 
888
                        $this->mConds['log_namespace'] = $ns;
 
889
                        $this->mConds['log_title'] = $title->getDBkey();
 
890
                }
 
891
                // Paranoia: avoid brute force searches (bug 17342)
 
892
                if( !$wgUser->isAllowed( 'deletedhistory' ) ) {
 
893
                        $this->mConds[] = $db->bitAnd('log_deleted', LogPage::DELETED_ACTION) . ' = 0';
 
894
                } else if( !$wgUser->isAllowed( 'suppressrevision' ) ) {
 
895
                        $this->mConds[] = $db->bitAnd('log_deleted', LogPage::SUPPRESSED_ACTION) .
 
896
                                ' != ' . LogPage::SUPPRESSED_ACTION;
 
897
                }
 
898
        }
 
899
 
 
900
        public function getQueryInfo() {
 
901
                global $wgOut;
 
902
                $tables = array( 'logging', 'user' );
 
903
                $this->mConds[] = 'user_id = log_user';
 
904
                $index = array();
 
905
                $options = array();
 
906
                # Add log_search table if there are conditions on it
 
907
                if( array_key_exists('ls_field',$this->mConds) ) {
 
908
                        $tables[] = 'log_search';
 
909
                        $index['log_search'] = 'ls_field_val';
 
910
                        $index['logging'] = 'PRIMARY';
 
911
                        $options[] = 'DISTINCT';
 
912
                # Avoid usage of the wrong index by limiting
 
913
                # the choices of available indexes. This mainly
 
914
                # avoids site-breaking filesorts.
 
915
                } else if( $this->title || $this->pattern || $this->user ) {
 
916
                        $index['logging'] = array( 'page_time', 'user_time' );
 
917
                        if( count($this->types) == 1 ) {
 
918
                                $index['logging'][] = 'log_user_type_time';
 
919
                        }
 
920
                } else if( count($this->types) == 1 ) {
 
921
                        $index['logging'] = 'type_time';
 
922
                } else {
 
923
                        $index['logging'] = 'times';
 
924
                }
 
925
                $options['USE INDEX'] = $index;
 
926
                # Don't show duplicate rows when using log_search
 
927
                $info = array(
 
928
                        'tables'     => $tables,
 
929
                        'fields'     => array( 'log_type', 'log_action', 'log_user', 'log_namespace',
 
930
                                'log_title', 'log_params', 'log_comment', 'log_id', 'log_deleted',
 
931
                                'log_timestamp', 'user_name', 'user_editcount' ),
 
932
                        'conds'      => $this->mConds,
 
933
                        'options'    => $options,
 
934
                        'join_conds' => array(
 
935
                                'user' => array( 'INNER JOIN', 'user_id=log_user' ),
 
936
                                'log_search' => array( 'INNER JOIN', 'ls_log_id=log_id' )
 
937
                        )
 
938
                );
 
939
                # Add ChangeTags filter query
 
940
                ChangeTags::modifyDisplayQuery( $info['tables'], $info['fields'], $info['conds'],
 
941
                        $info['join_conds'], $info['options'], $this->mTagFilter );
 
942
                return $info;
 
943
        }
 
944
 
 
945
        function getIndexField() {
 
946
                return 'log_timestamp';
 
947
        }
 
948
 
 
949
        public function getStartBody() {
 
950
                wfProfileIn( __METHOD__ );
 
951
                # Do a link batch query
 
952
                if( $this->getNumRows() > 0 ) {
 
953
                        $lb = new LinkBatch;
 
954
                        while( $row = $this->mResult->fetchObject() ) {
 
955
                                $lb->add( $row->log_namespace, $row->log_title );
 
956
                                $lb->addObj( Title::makeTitleSafe( NS_USER, $row->user_name ) );
 
957
                                $lb->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->user_name ) );
 
958
                        }
 
959
                        $lb->execute();
 
960
                        $this->mResult->seek( 0 );
 
961
                }
 
962
                wfProfileOut( __METHOD__ );
 
963
                return '';
 
964
        }
 
965
 
 
966
        public function formatRow( $row ) {
 
967
                return $this->mLogEventsList->logLine( $row );
 
968
        }
 
969
 
 
970
        public function getType() {
 
971
                return $this->types;
 
972
        }
 
973
 
 
974
        public function getUser() {
 
975
                return $this->user;
 
976
        }
 
977
 
 
978
        public function getPage() {
 
979
                return $this->title;
 
980
        }
 
981
 
 
982
        public function getPattern() {
 
983
                return $this->pattern;
 
984
        }
 
985
 
 
986
        public function getYear() {
 
987
                return $this->mYear;
 
988
        }
 
989
 
 
990
        public function getMonth() {
 
991
                return $this->mMonth;
 
992
        }
 
993
 
 
994
        public function getTagFilter() {
 
995
                return $this->mTagFilter;
 
996
        }
 
997
 
 
998
        public function doQuery() {
 
999
                // Workaround MySQL optimizer bug
 
1000
                $this->mDb->setBigSelects();
 
1001
                parent::doQuery();
 
1002
                $this->mDb->setBigSelects( 'default' );
 
1003
        }
 
1004
}
 
1005
 
 
1006
/**
 
1007
 * @deprecated
 
1008
 * @ingroup SpecialPage
 
1009
 */
 
1010
class LogReader {
 
1011
        var $pager;
 
1012
        /**
 
1013
         * @param $request WebRequest: for internal use use a FauxRequest object to pass arbitrary parameters.
 
1014
         */
 
1015
        function __construct( $request ) {
 
1016
                global $wgUser, $wgOut;
 
1017
                wfDeprecated(__METHOD__);
 
1018
                # Get parameters
 
1019
                $type = $request->getVal( 'type' );
 
1020
                $user = $request->getText( 'user' );
 
1021
                $title = $request->getText( 'page' );
 
1022
                $pattern = $request->getBool( 'pattern' );
 
1023
                $year = $request->getIntOrNull( 'year' );
 
1024
                $month = $request->getIntOrNull( 'month' );
 
1025
                $tagFilter = $request->getVal( 'tagfilter' );
 
1026
                # Don't let the user get stuck with a certain date
 
1027
                $skip = $request->getText( 'offset' ) || $request->getText( 'dir' ) == 'prev';
 
1028
                if( $skip ) {
 
1029
                        $year = '';
 
1030
                        $month = '';
 
1031
                }
 
1032
                # Use new list class to output results
 
1033
                $loglist = new LogEventsList( $wgUser->getSkin(), $wgOut, 0 );
 
1034
                $this->pager = new LogPager( $loglist, $type, $user, $title, $pattern, $year, $month, $tagFilter );
 
1035
        }
 
1036
 
 
1037
        /**
 
1038
        * Is there at least one row?
 
1039
        * @return bool
 
1040
        */
 
1041
        public function hasRows() {
 
1042
                return isset($this->pager) ? ($this->pager->getNumRows() > 0) : false;
 
1043
        }
 
1044
}
 
1045
 
 
1046
/**
 
1047
 * @deprecated
 
1048
 * @ingroup SpecialPage
 
1049
 */
 
1050
class LogViewer {
 
1051
        const NO_ACTION_LINK = 1;
 
1052
 
 
1053
        /**
 
1054
         * LogReader object
 
1055
         */
 
1056
        var $reader;
 
1057
 
 
1058
        /**
 
1059
         * @param &$reader LogReader: where to get our data from
 
1060
         * @param $flags Integer: Bitwise combination of flags:
 
1061
         *     LogEventsList::NO_ACTION_LINK   Don't show restore/unblock/block links
 
1062
         */
 
1063
        function __construct( &$reader, $flags = 0 ) {
 
1064
                wfDeprecated(__METHOD__);
 
1065
                $this->reader =& $reader;
 
1066
                $this->reader->pager->mLogEventsList->flags = $flags;
 
1067
                # Aliases for shorter code...
 
1068
                $this->pager =& $this->reader->pager;
 
1069
                $this->list =& $this->reader->pager->mLogEventsList;
 
1070
        }
 
1071
 
 
1072
        /**
 
1073
         * Take over the whole output page in $wgOut with the log display.
 
1074
         */
 
1075
        public function show() {
 
1076
                # Set title and add header
 
1077
                $this->list->showHeader( $pager->getType() );
 
1078
                # Show form options
 
1079
                $this->list->showOptions( $this->pager->getType(), $this->pager->getUser(), $this->pager->getPage(),
 
1080
                        $this->pager->getPattern(), $this->pager->getYear(), $this->pager->getMonth() );
 
1081
                # Insert list
 
1082
                $logBody = $this->pager->getBody();
 
1083
                if( $logBody ) {
 
1084
                        $wgOut->addHTML(
 
1085
                                $this->pager->getNavigationBar() .
 
1086
                                $this->list->beginLogEventsList() .
 
1087
                                $logBody .
 
1088
                                $this->list->endLogEventsList() .
 
1089
                                $this->pager->getNavigationBar()
 
1090
                        );
 
1091
                } else {
 
1092
                        $wgOut->addWikiMsg( 'logempty' );
 
1093
                }
 
1094
        }
 
1095
 
 
1096
        /**
 
1097
         * Output just the list of entries given by the linked LogReader,
 
1098
         * with extraneous UI elements. Use for displaying log fragments in
 
1099
         * another page (eg at Special:Undelete)
 
1100
         * @param $out OutputPage: where to send output
 
1101
         */
 
1102
        public function showList( &$out ) {
 
1103
                $logBody = $this->pager->getBody();
 
1104
                if( $logBody ) {
 
1105
                        $out->addHTML(
 
1106
                                $this->list->beginLogEventsList() .
 
1107
                                $logBody .
 
1108
                                $this->list->endLogEventsList()
 
1109
                        );
 
1110
                } else {
 
1111
                        $out->addWikiMsg( 'logempty' );
 
1112
                }
 
1113
        }
 
1114
}