Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 153
0.00% covered (danger)
0.00%
0 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
FlaggedRevsXML
0.00% covered (danger)
0.00%
0 / 153
0.00% covered (danger)
0.00%
0 / 13
1332
0.00% covered (danger)
0.00%
0 / 1
 getNamespaceMenu
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
56
 getDefaultFilterMenu
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getRestrictionFilterMenu
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
30
 addTagRatings
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
6
 prettyRatingBox
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
132
 ratingArrow
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 diffToggle
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 draftStatusIcon
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 stableStatusIcon
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 lockStatusIcon
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
 pendingEditNotice
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 pendingEditNoticeMessage
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 stabilityLogExcerpt
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3use MediaWiki\Html\Html;
4use MediaWiki\MediaWikiServices;
5use MediaWiki\Title\Title;
6
7/**
8 * Class containing utility XML functions for a FlaggedRevs.
9 * Includes functions for selectors, icons, notices, CSS, and form aspects.
10 */
11class FlaggedRevsXML {
12
13    /**
14     * Get a selector of reviewable namespaces
15     * @param int|null $selected namespace selected
16     * @param string|null $all Value of an item denoting all namespaces, or null to omit
17     */
18    public static function getNamespaceMenu( ?int $selected = null, ?string $all = null ): string {
19        $s = "<label for='namespace'>" . wfMessage( 'namespace' )->escaped() . "</label>";
20        # No namespace selected; let exact match work without hitting Main
21        $selected ??= '';
22        $s .= "\n<select id='namespace' name='namespace' class='namespaceselector'>\n";
23        $arr = MediaWikiServices::getInstance()->getContentLanguage()->getFormattedNamespaces();
24        if ( $all !== null ) {
25            $arr = [ $all => wfMessage( 'namespacesall' )->text() ] + $arr; // should be first
26        }
27        foreach ( $arr as $index => $name ) {
28            # Content pages only (except 'all')
29            if ( $index !== $all && !FlaggedRevs::isReviewNamespace( $index ) ) {
30                continue;
31            }
32            $name = $index !== 0 ? $name : wfMessage( 'blanknamespace' )->text();
33            if ( $index === $selected ) {
34                $s .= "\t" . Html::element( 'option', [ 'value' => $index,
35                    "selected" => "selected" ], $name ) . "\n";
36            } else {
37                $s .= "\t" . Html::element( 'option', [ 'value' => $index ], $name ) . "\n";
38            }
39        }
40        $s .= "</select>\n";
41        return $s;
42    }
43
44    /**
45     * Get a <select> of default page version (stable or draft). Used for filters.
46     * @param int|null $selected (0=draft, 1=stable, null=either )
47     */
48    public static function getDefaultFilterMenu( ?int $selected = null ): string {
49        $s = Xml::option( wfMessage( 'revreview-def-all' )->text(), '', ( $selected ?? '' ) === '' );
50        $s .= Xml::option( wfMessage( 'revreview-def-stable' )->text(), '1', $selected === 1 );
51        $s .= Xml::option( wfMessage( 'revreview-def-draft' )->text(), '0', $selected === 0 );
52        return Xml::label( wfMessage( 'revreview-defaultfilter' )->text(), 'wpStable' ) . "\n" .
53            Html::rawElement( 'select', [ 'name' => 'stable', 'id' => 'wpStable' ], $s ) . "\n";
54    }
55
56    /**
57     * Get a <select> of options of 'autoreview' restriction levels. Used for filters.
58     * @param string|null $selected (null or empty string for "any", 'none' for none)
59     */
60    public static function getRestrictionFilterMenu( ?string $selected = '' ): string {
61        if ( $selected === null ) {
62            $selected = ''; // "all"
63        }
64        $s = Xml::label( wfMessage( 'revreview-restrictfilter' )->text(), 'wpRestriction' ) . "\n";
65        $s .= Html::openElement( 'select',
66            [ 'name' => 'restriction', 'id' => 'wpRestriction' ] );
67        $s .= Xml::option( wfMessage( 'revreview-restriction-any' )->text(), '', $selected == '' );
68        if ( !FlaggedRevs::useProtectionLevels() ) {
69            # All "protected" pages have a protection level, not "none"
70            $s .= Xml::option( wfMessage( 'revreview-restriction-none' )->text(),
71                'none', $selected == 'none' );
72        }
73        foreach ( FlaggedRevs::getRestrictionLevels() as $perm ) {
74            // Give grep a chance to find the usages:
75            // revreview-restriction-any, revreview-restriction-none
76            $key = "revreview-restriction-$perm";
77            $msg = wfMessage( $key )->isDisabled() ? $perm : wfMessage( $key )->text();
78            $s .= Xml::option( $msg, $perm, $selected == $perm );
79        }
80        $s .= Html::closeElement( 'select' ) . "\n";
81        return $s;
82    }
83
84    /**
85     * Generates a review box/tag
86     * @param array<string,int> $flags
87     */
88    public static function addTagRatings( array $flags ): string {
89        $tag = Html::openElement(
90            'table',
91            [
92                'id' => 'mw-fr-revisionratings-box',
93                'style' => 'margin: auto;',
94                'class' => 'flaggedrevs-color-1',
95                'cellpadding' => '0',
96            ]
97        );
98        $quality = FlaggedRevs::getTagName();
99
100        if ( !FlaggedRevs::useOnlyIfProtected() ) {
101            // Give grep a chance to find the usages:
102            // revreview-accuracy-0, revreview-accuracy-1, revreview-accuracy-2,
103            // revreview-accuracy-3, revreview-accuracy-4
104            $level = $flags[$quality] ?? 0;
105            $encValueText = wfMessage( "revreview-$quality-$level" )->escaped();
106
107            $levelmarker = $level * 20 + 20;
108            // Give grep a chance to find the usages:
109            // revreview-accuracy
110            $tag .= "<tr><td class='fr-text' style='vertical-align: middle;'>" .
111                wfMessage( "revreview-$quality" )->escaped() .
112                "</td><td class='fr-value$levelmarker' style='vertical-align: middle;'>" .
113                $encValueText . "</td></tr>\n";
114            $tag .= Html::closeElement( 'table' );
115        }
116        return $tag;
117    }
118
119    /**
120     * Generates a review box using a table using FlaggedRevsXML::addTagRatings()
121     * @param FlaggedRevision $frev the reviewed version
122     * @param string $shtml Short message HTML
123     * @param int $revsSince revisions since review
124     * @param string $type (stable/draft/oldstable)
125     * @param bool $synced does stable=current and this is one of them?
126     */
127    public static function prettyRatingBox(
128        FlaggedRevision $frev,
129        string $shtml,
130        int $revsSince,
131        string $type = 'oldstable',
132        bool $synced = false
133    ): string {
134        global $wgLang;
135        $flags = $frev->getTags();
136        $time = $wgLang->date( $frev->getTimestamp(), true );
137        # Construct some tagging
138        if ( $synced && ( $type == 'stable' || $type == 'draft' ) ) {
139            $msg = 'revreview-basic-same';
140            $html = wfMessage( $msg, $frev->getRevId(), $time )->numParams( $revsSince )->parse();
141        } elseif ( $type == 'oldstable' ) {
142            $msg = 'revreview-basic-old';
143            $html = wfMessage( $msg, $frev->getRevId(), $time )->parse();
144        } else {
145            $msg = $type === 'stable' ? 'revreview-basic' : 'revreview-newest-basic';
146            # For searching: uses messages 'revreview-basic-i', 'revreview-newest-basic-i'
147            $msg .= !$revsSince ? '-i' : '';
148            $html = wfMessage( $msg, $frev->getRevId(), $time )->numParams( $revsSince )->parse();
149        }
150        # Make fancy box...
151        $box = '<div class="flaggedrevs_short_basic">';
152        $box .= $shtml . self::ratingArrow();
153        $box .= "</div>\n";
154        // For rel-absolute child div (the fly-out)
155        $box .= '<div id="mw-fr-revisiondetails-wrapper" style="position:relative;">';
156        $box .= Html::openElement(
157            'div',
158            [
159                'id'    => 'mw-fr-revisiondetails',
160                'class' => 'flaggedrevs_short_details',
161                'style' => 'display:none'
162            ]
163        );
164        $box .= $html; // details text
165        # Add any rating tags as needed...
166        if ( $flags && !FlaggedRevs::binaryFlagging() ) {
167            # Don't show the ratings on draft views
168            if ( $type == 'stable' || $type == 'oldstable' ) {
169                $box .= '<p>' . self::addTagRatings( $flags ) . '</p>';
170            }
171        }
172        $box .= Html::closeElement( 'div' ) . "\n";
173        $box .= "</div>\n";
174        return $box;
175    }
176
177    /**
178     * Generates JS toggle arrow icon
179     */
180    private static function ratingArrow(): string {
181        return ( new OOUI\IndicatorWidget(
182            [
183                'indicator' => 'down',
184                'classes' => [ 'fr-toggle-arrow' ],
185                'id' => 'mw-fr-revisiontoggle',
186                'title' => wfMessage( 'revreview-toggle-title' )->text(),
187            ]
188        ) )->toString();
189    }
190
191    /**
192     * Generates the "(show/hide)" diff toggle. With JS disabled, it functions as a link to the diff.
193     * @param Title $title
194     * @param int $fromrev
195     * @param int $torev
196     * @param string|null $multiNotice Message about intermediate revisions
197     */
198    public static function diffToggle( Title $title, int $fromrev, int $torev, string $multiNotice = null ): string {
199        // Construct a link to the diff
200        $href = $title->getFullURL( [ 'diff' => $torev, 'oldid' => $fromrev ] );
201
202        $toggle = Html::element( 'a', [
203            'class' => 'fr-toggle-text',
204            'title' => wfMessage( 'revreview-diff-toggle-title' )->text(),
205            'href' => $href,
206            'data-mw-fromrev' => $fromrev,
207            'data-mw-torev' => $torev,
208            'data-mw-multinotice' => $multiNotice,
209        ], wfMessage( 'revreview-diff-toggle-show' )->text() );
210
211        return '<span id="mw-fr-difftoggle">' .
212            wfMessage( 'parentheses' )->rawParams( $toggle )->escaped() . '</span>';
213    }
214
215    /**
216     * Creates CSS draft page icon
217     */
218    public static function draftStatusIcon(): string {
219        $encTitle = wfMessage( 'revreview-draft-title' )->text();
220        return ( new OOUI\IconWidget(
221            [
222                'icon' => 'block',
223                'classes' => [ 'flaggedrevs-icon' ],
224                'title' => $encTitle,
225            ]
226        ) )->toString();
227    }
228
229    /**
230     * Creates CSS stable page icon
231     */
232    public static function stableStatusIcon(): string {
233        $encTitle = wfMessage( 'revreview-basic-title' )->text();
234        return ( new OOUI\IconWidget(
235            [
236                'icon' => 'eye',
237                'classes' => [ 'flaggedrevs-icon' ],
238                'title' => $encTitle,
239            ]
240        ) )->toString();
241    }
242
243    /**
244     * Creates CSS lock icon if page is locked/unlocked
245     */
246    public static function lockStatusIcon( FlaggableWikiPage $flaggedArticle ): string {
247        if ( $flaggedArticle->isPageLocked() ) {
248            $encTitle = wfMessage( 'revreview-locked-title' )->text();
249            $icon = 'articleSearch';
250        } elseif ( $flaggedArticle->isPageUnlocked() ) {
251            $encTitle = wfMessage( 'revreview-unlocked-title' )->text();
252            $icon = 'articleCheck';
253        } else {
254            return '';
255        }
256        return ( new OOUI\IconWidget(
257            [
258                'icon' => $icon,
259                'classes' => [ 'flaggedrevs-icon' ],
260                'title' => $encTitle,
261            ]
262        ) )->toString();
263    }
264
265    /**
266     * Creates "stable rev reviewed on"/"x pending edits" message
267     */
268    public static function pendingEditNotice( FlaggedRevision $frev, int $revsSince ): string {
269        $msg = self::pendingEditNoticeMessage( $frev, $revsSince );
270        return $msg->parse();
271    }
272
273    /**
274     * Same as pendingEditNotice(), but returns a Message object.
275     */
276    public static function pendingEditNoticeMessage( FlaggedRevision $frev, int $revsSince ): Message {
277        global $wgLang;
278        $time = $wgLang->date( $frev->getTimestamp(), true );
279        # Add message text for pending edits
280        return wfMessage( 'revreview-pending-basic', $frev->getRevId(), $time )->numParams( $revsSince );
281    }
282
283    /**
284     * Creates a stability log excerpt
285     */
286    public static function stabilityLogExcerpt( Title $title ): string {
287        $logHtml = '';
288        $params = [
289            'lim'   => 1,
290            'flags' => LogEventsList::NO_EXTRA_USER_LINKS
291        ];
292        LogEventsList::showLogExtract( $logHtml, 'stable',
293            $title->getPrefixedText(), '', $params );
294        return Html::rawElement(
295            'div',
296            [ 'id' => 'mw-fr-logexcerpt' ],
297            $logHtml
298        );
299    }
300
301}