Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 251
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
Hooks
0.00% covered (danger)
0.00%
0 / 251
0.00% covered (danger)
0.00%
0 / 9
2550
0.00% covered (danger)
0.00%
0 / 1
 onSidebarBeforeOutput
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
20
 getPortlet
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 1
210
 onSiteNoticeAfter
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
182
 renderBookCreatorBox
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
12
 getBookCreatorBoxContent
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getBookCreatorBoxAddRemoveLink
0.00% covered (danger)
0.00%
0 / 59
0.00% covered (danger)
0.00%
0 / 1
72
 getBookCreatorBoxShowBookLink
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
6
 getBookCreatorBoxSuggestLink
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
12
 onOutputPageCheckLastModified
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * Collection Extension for MediaWiki
4 *
5 * Copyright (C) PediaPress GmbH
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * http://www.gnu.org/copyleft/gpl.html
21 */
22
23namespace MediaWiki\Extension\Collection;
24
25use MediaWiki\Hook\OutputPageCheckLastModifiedHook;
26use MediaWiki\Hook\SidebarBeforeOutputHook;
27use MediaWiki\Hook\SiteNoticeAfterHook;
28use MediaWiki\Html\Html;
29use MediaWiki\Html\TemplateParser;
30use MediaWiki\Linker\Linker;
31use MediaWiki\MainConfigNames;
32use MediaWiki\Output\OutputPage;
33use MediaWiki\Session\SessionManager;
34use MediaWiki\SpecialPage\SpecialPage;
35use MediaWiki\Title\Title;
36use RequestContext;
37use Skin;
38
39class Hooks implements
40    SidebarBeforeOutputHook,
41    SiteNoticeAfterHook,
42    OutputPageCheckLastModifiedHook
43{
44    /**
45     * Callback for SidebarBeforeOutput hook
46     *
47     * @param Skin $skin
48     * @param array &$sidebar
49     */
50    public function onSidebarBeforeOutput( $skin, &$sidebar ): void {
51        global $wgCollectionPortletForLoggedInUsersOnly;
52
53        if ( !$wgCollectionPortletForLoggedInUsersOnly || $skin->getUser()->isRegistered() ) {
54
55            $portlet = self::getPortlet( $skin );
56
57            if ( $portlet ) {
58                // Unset 'print' item. We have moved it to our own section.
59                unset( $sidebar['TOOLBOX']['print'] );
60
61                // Add our section
62                $sidebar[ 'coll-print_export' ] = $portlet;
63            }
64        }
65    }
66
67    /**
68     * Return HTML-code to be inserted as portlet
69     *
70     * @param Skin $sk
71     *
72     * @return array[]|false
73     */
74    public static function getPortlet( $sk ) {
75        global $wgCollectionArticleNamespaces;
76        global $wgCollectionFormats;
77        global $wgCollectionPortletFormats;
78
79        $title = $sk->getTitle();
80
81        if ( $title === null || !$title->exists() ) {
82            return false;
83        }
84
85        $namespace = $title->getNamespace();
86
87        if ( !in_array( $namespace, $wgCollectionArticleNamespaces )
88            && $namespace != NS_CATEGORY ) {
89            return false;
90        }
91
92        $action = $sk->getRequest()->getVal( 'action', 'view' );
93        if ( $action != 'view' && $action != 'purge' ) {
94            return false;
95        }
96
97        $out = [];
98
99        $booktitle = SpecialPage::getTitleFor( 'Book' );
100        if ( !Session::isEnabled() ) {
101            if ( !$sk->getConfig()->get( 'CollectionDisableSidebarLink' ) ) {
102                $out[] = [
103                    'text' => $sk->msg( 'coll-create_a_book' )->escaped(),
104                    'id' => 'coll-create_a_book',
105                    'href' => $booktitle->getLocalURL(
106                        [ 'bookcmd' => 'book_creator', 'referer' => $title->getPrefixedText() ]
107                        ),
108                ];
109            }
110        } else {
111            $out[] = [
112                'text' => $sk->msg( 'coll-book_creator_disable' )->escaped(),
113                'id' => 'coll-book_creator_disable',
114                'href' => $booktitle->getLocalURL(
115                    [
116                        'bookcmd' => 'stop_book_creator',
117                        'referer' => $title->getPrefixedText(),
118                    ]
119                ),
120            ];
121        }
122
123        $params = [
124            'bookcmd' => 'render_article',
125            'arttitle' => $title->getPrefixedText(),
126            'returnto' => $title->getPrefixedText(),
127        ];
128
129        $oldid = $sk->getRequest()->getVal( 'oldid' );
130        if ( $oldid ) {
131            $params['oldid'] = $oldid;
132        } else {
133            $params['oldid'] = $title->getLatestRevID();
134        }
135
136        foreach ( $wgCollectionPortletFormats as $writer ) {
137            $params['writer'] = $writer;
138            $out[] = [
139                'text' => $sk->msg( 'coll-download_as', $wgCollectionFormats[$writer] )->escaped(),
140                'id' => 'coll-download-as-' . $writer,
141                'href' => $booktitle->getLocalURL( $params ),
142            ];
143        }
144
145        // Move the 'printable' link into our section for consistency
146        if ( $action == 'view' || $action == 'purge' ) {
147            if ( !$sk->getOutput()->isPrintable() ) {
148                $out[] = [ 'text' => $sk->msg( 'printableversion' )->text(),
149                    'id' => 't-print',
150                    'href' => $title->getLocalURL( [ 'printable' => 'yes' ] )
151                ];
152            }
153        }
154
155        return $out;
156    }
157
158    /**
159     * Callback for hook SiteNoticeAfter
160     * @param string &$siteNotice
161     * @param Skin $skin
162     */
163    public function onSiteNoticeAfter( &$siteNotice, $skin ) {
164        global $wgCollectionArticleNamespaces;
165
166        $request = $skin->getRequest();
167        $title = $skin->getTitle();
168
169        $action = $request->getVal( 'action' );
170        if ( $action != '' && $action != 'view' && $action != 'purge' ) {
171            return;
172        }
173
174        $session = SessionManager::getGlobalSession();
175
176        if (
177            !isset( $session['wsCollection'] ) ||
178            !isset( $session['wsCollection']['enabled'] ) ||
179            !$session['wsCollection']['enabled']
180        ) {
181            return;
182        }
183
184        if ( $title->isSpecial( 'Book' ) ) {
185            $cmd = $request->getVal( 'bookcmd', '' );
186            if ( $cmd == 'suggest' ) {
187                $siteNotice .= self::renderBookCreatorBox( $title, 'suggest' );
188            } elseif ( $cmd == '' ) {
189                $siteNotice .= self::renderBookCreatorBox( $title, 'showbook' );
190            }
191            return;
192        }
193
194        if ( !$title->exists() ) {
195            return;
196        }
197
198        $namespace = $title->getNamespace();
199        if ( !in_array( $namespace, $wgCollectionArticleNamespaces )
200            && $namespace != NS_CATEGORY ) {
201            return;
202        }
203
204        $siteNotice .= self::renderBookCreatorBox( $title );
205    }
206
207    /**
208     * @param Title $title
209     * @param string $mode
210     * @return string
211     */
212    public static function renderBookCreatorBox( Title $title, $mode = '' ) {
213        $templateParser = new TemplateParser( dirname( __DIR__ ) . '/templates' );
214        $context = RequestContext::getMain();
215
216        $imagePath = $context->getConfig()->get( MainConfigNames::ExtensionAssetsPath ) . '/Collection/images';
217        $ptext = $title->getPrefixedText();
218        $oldid = $context->getRequest()->getInt( 'oldid', 0 );
219        if ( $oldid == $title->getLatestRevID() ) {
220            $oldid = 0;
221        }
222
223        $out = $context->getOutput();
224        $out->addModules( 'ext.collection.bookcreator' );
225        $out->addModuleStyles( 'ext.collection.bookcreator.styles' );
226
227        $addRemoveState = $mode;
228        $helpPage = Title::newFromText( $context->msg( 'coll-helppage' )->text() );
229
230        return $templateParser->processTemplate( 'create-book', [
231            "actionsHtml" => self::getBookCreatorBoxContent( $title, $addRemoveState, $oldid ),
232            "imagePath" => $imagePath,
233            "title" => $context->msg( 'coll-book_creator' )->text(),
234            "disable" => [
235                "url" => SpecialPage::getTitleFor( 'Book' )->getLocalUrl(
236                    [ 'bookcmd' => 'stop_book_creator', 'referer' => $ptext ]
237                ),
238                "title" => $context->msg( 'coll-book_creator_disable_tooltip' )->text(),
239                "label" => $context->msg( 'coll-disable' )->escaped(),
240            ],
241            "help" => [
242                "url" => $helpPage ? $helpPage->getLocalUrl() : '',
243                "label" => $context->msg( 'coll-help' )->escaped(),
244                "title" => $context->msg( 'coll-help_tooltip' )->text(),
245                "icon" => $imagePath . '/silk-help.png',
246            ]
247        ] );
248    }
249
250    /**
251     * @param Title $title
252     * @param string|null $hint Defaults to null
253     * @param null|int $oldid
254     * @return string
255     */
256    public static function getBookCreatorBoxContent( Title $title, $hint = null, $oldid = null ) {
257        global $wgExtensionAssetsPath;
258
259        $imagePath = "$wgExtensionAssetsPath/Collection/images";
260
261        return self::getBookCreatorBoxAddRemoveLink( $imagePath, $hint, $title, $oldid )
262            . self::getBookCreatorBoxShowBookLink( $imagePath, $hint )
263            . self::getBookCreatorBoxSuggestLink( $imagePath, $hint );
264    }
265
266    /**
267     * @param string $imagePath
268     * @param string $hint
269     * @param Title $title
270     * @param int $oldid
271     * @return string
272     */
273    public static function getBookCreatorBoxAddRemoveLink(
274        $imagePath,
275        $hint,
276        Title $title,
277        $oldid
278    ) {
279        $namespace = $title->getNamespace();
280        $ptext = $title->getPrefixedText();
281
282        if ( $hint == 'suggest' || $hint == 'showbook' ) {
283            return Html::rawElement( 'span',
284                [ 'style' => 'color: #777;' ],
285                Html::element( 'img',
286                    [
287                        'src' => "$imagePath/disabled.png",
288                        'alt' => '',
289                        'width' => '16',
290                        'height' => '16',
291                        'style' => 'vertical-align: text-bottom',
292                    ]
293                )
294                . '&#160;' . wfMessage( 'coll-not_addable' )->escaped()
295            );
296        }
297
298        if ( $hint == 'addcategory' || $namespace == NS_CATEGORY ) {
299            $id = 'coll-add_category';
300            $icon = 'silk-add.png';
301            $captionMsg = 'coll-add_category';
302            $tooltipMsg = 'coll-add_category_tooltip';
303            $query = [ 'bookcmd' => 'add_category', 'cattitle' => $title->getText() ];
304            $onclick = "collectionCall('addcategory', mw.config.get('wgNamespaceNumber')," .
305                "mw.config.get('wgTitle')]); return false;";
306        } else {
307            $collectionArgsJs = "mw.config.get('wgNamespaceNumber'), mw.config.get('wgTitle'), " .
308                Html::encodeJsVar( $oldid );
309            if ( $hint == 'addarticle'
310                || ( $hint == '' && Session::findArticle( $ptext, $oldid ) == -1 ) ) {
311                $id = 'coll-add_article';
312                $icon = 'silk-add.png';
313                $captionMsg = 'coll-add_this_page';
314                $tooltipMsg = 'coll-add_page_tooltip';
315                $query = [ 'bookcmd' => 'add_article', 'arttitle' => $ptext, 'oldid' => $oldid ];
316                $onclick = "collectionCall('addarticle', " . $collectionArgsJs . "); return false;";
317            } else {
318                $id = 'coll-remove_article';
319                $icon = 'silk-remove.png';
320                $captionMsg = 'coll-remove_this_page';
321                $tooltipMsg = 'coll-remove_page_tooltip';
322                $query = [ 'bookcmd' => 'remove_article', 'arttitle' => $ptext, 'oldid' => $oldid ];
323                $onclick = "collectionCall('removearticle', " . $collectionArgsJs . "); return false;";
324            }
325        }
326
327        return Linker::linkKnown(
328            SpecialPage::getTitleFor( 'Book' ),
329            Html::element( 'img',
330                [
331                    'src' => "$imagePath/$icon",
332                    'alt' => '',
333                    'width' => '16',
334                    'height' => '16',
335                ]
336            )
337            . '&#160;' . wfMessage( $captionMsg )->escaped(),
338            [
339                'id' => $id,
340                'rel' => 'nofollow',
341                'title' => wfMessage( $tooltipMsg )->text(),
342                'onclick' => $onclick,
343            ],
344            $query
345        );
346    }
347
348    /**
349     * @param string $imagePath
350     * @param string $hint
351     * @return string
352     */
353    public static function getBookCreatorBoxShowBookLink( $imagePath, $hint ) {
354        $numArticles = Session::countArticles();
355
356        if ( $hint == 'showbook' ) {
357            return Html::rawElement( 'strong',
358                [
359                    'class' => 'collection-creatorbox-iconlink',
360                ],
361                Html::element( 'img',
362                    [
363                        'src' => "$imagePath/silk-book_open.png",
364                        'alt' => '',
365                        'width' => '16',
366                        'height' => '16',
367                    ]
368                )
369                . '&#160;' . wfMessage( 'coll-show_collection' )->escaped()
370                . ' (' . wfMessage( 'coll-n_pages' )->numParams( $numArticles )->escaped() . ')'
371            ); // @todo FIXME: Hard coded parentheses.
372        } else {
373            return Linker::linkKnown(
374                SpecialPage::getTitleFor( 'Book' ),
375                Html::element( 'img',
376                    [
377                        'src' => "$imagePath/silk-book_open.png",
378                        'alt' => '',
379                        'width' => '16',
380                        'height' => '16',
381                    ]
382                )
383                . '&#160;' . wfMessage( 'coll-show_collection' )->escaped()
384                    . ' (' . wfMessage( 'coll-n_pages' )->numParams( $numArticles )->escaped() . ')',
385                [
386                    'rel' => 'nofollow',
387                    'title' => wfMessage( 'coll-show_collection_tooltip' )->text(),
388                    'class' => 'collection-creatorbox-iconlink',
389                ]
390            ); // @todo FIXME: Hard coded parentheses.
391        }
392    }
393
394    /**
395     * @param string $imagePath
396     * @param string $hint
397     * @return string
398     */
399    public static function getBookCreatorBoxSuggestLink( $imagePath, $hint ) {
400        if ( wfMessage( 'coll-suggest_enabled' )->escaped() != '1' ) {
401            return '';
402        }
403
404        if ( $hint == 'suggest' ) {
405            return Html::rawElement( 'strong',
406                [
407                    'class' => 'collection-creatorbox-iconlink',
408                ],
409                Html::element( 'img',
410                    [
411                        'src' => "$imagePath/silk-wand.png",
412                        'alt' => '',
413                        'width' => '16',
414                        'height' => '16',
415                        'style' => 'vertical-align: text-bottom',
416                    ]
417                )
418                . '&#160;' . wfMessage( 'coll-make_suggestions' )->escaped()
419            );
420        } else {
421            return Linker::linkKnown(
422                SpecialPage::getTitleFor( 'Book' ),
423                Html::element( 'img',
424                    [
425                        'src' => "$imagePath/silk-wand.png",
426                        'alt' => '',
427                        'width' => '16',
428                        'height' => '16',
429                        'style' => 'vertical-align: text-bottom',
430                    ]
431                )
432                . '&#160;' . wfMessage( 'coll-make_suggestions' )->escaped(),
433                [
434                    'rel' => 'nofollow',
435                    'title' => wfMessage( 'coll-make_suggestions_tooltip' )->text(),
436                    'class' => 'collection-creatorbox-iconlink',
437                ],
438                [ 'bookcmd' => 'suggest' ]
439            );
440        }
441    }
442
443    /**
444     * OutputPageCheckLastModified hook
445     * @param array &$modifiedTimes
446     * @param OutputPage $out
447     */
448    public function onOutputPageCheckLastModified( &$modifiedTimes, $out ) {
449        $session = SessionManager::getGlobalSession();
450        if ( isset( $session['wsCollection']['timestamp'] ) ) {
451            $modifiedTimes['collection'] = $session['wsCollection']['timestamp'];
452        }
453    }
454}