Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.83% covered (success)
95.83%
23 / 24
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
MobileFormatter
95.83% covered (success)
95.83%
23 / 24
75.00% covered (warning)
75.00%
3 / 4
10
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 applyTransforms
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 parseItemsToRemove
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
5.01
 canApply
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3use HtmlFormatter\HtmlFormatter;
4use MediaWiki\Config\Config;
5use MediaWiki\Title\Title;
6use MobileFrontend\Transforms\IMobileTransform;
7use Wikimedia\Parsoid\Utils\DOMCompat;
8
9/**
10 * Converts HTML into a mobile-friendly version
11 */
12class MobileFormatter extends HtmlFormatter {
13
14    /**
15     * @var Title
16     */
17    protected $title;
18
19    /**
20     * @var Config
21     */
22    private $config;
23
24    /**
25     * @var MobileContext
26     */
27    private $context;
28
29    /**
30     * @param string $html Text to process
31     * @param Title $title Title to which $html belongs
32     * @param Config $config
33     * @param MobileContext $context
34     */
35    public function __construct(
36        $html, Title $title, Config $config, MobileContext $context
37    ) {
38        parent::__construct( $html );
39
40        $this->title = $title;
41        $this->context = $context;
42        $this->config = $config;
43    }
44
45    /**
46     * Performs various transformations to the content to make it appropriate for mobile devices.
47     * @param array<IMobileTransform> $transforms lit of transforms to be sequentually applied
48     *   to html DOM
49     */
50    public function applyTransforms( array $transforms ) {
51        // Apply all removals before continuing with transforms (see T185040 for example)
52        $this->filterContent();
53
54        $doc = $this->getDoc();
55        $body = DOMCompat::querySelector( $doc, 'body' );
56
57        foreach ( $transforms as $transform ) {
58            $transform->apply( $body );
59        }
60    }
61
62    /**
63     * @inheritDoc
64     */
65    protected function parseItemsToRemove(): array {
66        $removals = parent::parseItemsToRemove();
67
68        // Remove specified content in content namespaces
69        if ( in_array( $this->title->getNamespace(), $this->config->get( 'ContentNamespaces' ), true ) ) {
70            $mfRemovableClasses = $this->config->get( 'MFRemovableClasses' );
71            $removableClasses = $mfRemovableClasses['base'];
72            if ( $this->context->isBetaGroupMember() ) {
73                $removableClasses = array_merge( $removableClasses, $mfRemovableClasses['beta'] );
74            }
75
76            foreach ( $removableClasses as $itemToRemove ) {
77                $type = '';
78                $rawName = '';
79                if ( $this->parseSelector( $itemToRemove, $type, $rawName ) ) {
80                    $removals[$type][] = $rawName;
81                }
82            }
83        }
84
85        return $removals;
86    }
87
88    /**
89     * Check whether the MobileFormatter can be applied to the text of a page.
90     * @param string $text
91     * @param array $options with 'maxHeadings' and 'maxImages' keys that limit the MobileFormatter
92     *  to pages with less than or equal to that number of headings and images.
93     * @return bool
94     */
95    public static function canApply( $text, $options ) {
96        $headings = preg_match_all( '/<[hH][1-6]/', $text );
97        $imgs = preg_match_all( '/<img/', $text );
98        return $headings <= $options['maxHeadings'] && $imgs <= $options['maxImages'];
99    }
100}