Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 91
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
CargoTableFormat
0.00% covered (danger)
0.00%
0 / 91
0.00% covered (danger)
0.00%
0 / 3
1482
0.00% covered (danger)
0.00%
0 / 1
 allowedParameters
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getHelperDataForMerging
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
132
 display
0.00% covered (danger)
0.00%
0 / 65
0.00% covered (danger)
0.00%
0 / 1
702
1<?php
2/**
3 * @author Yaron Koren
4 * @ingroup Cargo
5 */
6
7use MediaWiki\Html\Html;
8use MediaWiki\MediaWikiServices;
9use MediaWiki\Title\Title;
10
11class CargoTableFormat extends CargoDisplayFormat {
12
13    public static function allowedParameters() {
14        return [
15            'merge similar cells' => [ 'type' => 'boolean' ],
16            'edit link' => [ 'type' => 'boolean' ],
17        ];
18    }
19
20    /**
21     * Creates helper data structures that make merging cells
22     * easier, if it's going to be done.
23     */
24    private function getHelperDataForMerging( $formattedValuesTable ) {
25        $duplicateValuesInTable = [];
26        $blankedCells = [];
27        $numRows = count( $formattedValuesTable );
28        foreach ( $formattedValuesTable as $rowNum => $row ) {
29            foreach ( $row as $columnNum => $value ) {
30                if ( strpos( $columnNum, '__' ) !== false ) {
31                    continue;
32                }
33                if ( array_key_exists( $rowNum, $blankedCells ) && in_array( $columnNum, $blankedCells[$rowNum] ) ) {
34                    continue;
35                }
36                $numMatches = 0;
37                $nextRowNum = $rowNum;
38                while (
39                    ( ++$nextRowNum < $numRows ) &&
40                    ( $formattedValuesTable[$nextRowNum][$columnNum] == $value )
41                ) {
42                    $numMatches++;
43                    if ( !array_key_exists( $nextRowNum, $blankedCells ) ) {
44                        $blankedCells[$nextRowNum] = [];
45                    }
46                    $blankedCells[$nextRowNum][] = $columnNum;
47                }
48                if ( $numMatches > 0 ) {
49                    if ( !array_key_exists( $rowNum, $duplicateValuesInTable ) ) {
50                        $duplicateValuesInTable[$rowNum] = [];
51                    }
52                    $duplicateValuesInTable[$rowNum][$columnNum] = $numMatches + 1;
53                }
54            }
55        }
56
57        return [ $duplicateValuesInTable, $blankedCells ];
58    }
59
60    /**
61     * @param array $valuesTable Unused
62     * @param array $formattedValuesTable
63     * @param array $fieldDescriptions
64     * @param array $displayParams Unused
65     * @return string HTML
66     */
67    public function display( $valuesTable, $formattedValuesTable, $fieldDescriptions, $displayParams ) {
68        $this->mOutput->addModules( [ 'ext.cargo.main', 'jquery.tablesorter' ] );
69        $this->mOutput->addModuleStyles( [ 'jquery.tablesorter.styles' ] );
70
71        $mergeSimilarCells = false;
72        if ( array_key_exists( 'merge similar cells', $displayParams ) ) {
73            $mergeSimilarCells = strtolower( $displayParams['merge similar cells'] ) == 'yes';
74        }
75        $editLink = false;
76        $linkRenderer = null;
77        if ( array_key_exists( 'edit link', $displayParams ) ) {
78            $editLink = strtolower( $displayParams['edit link'] ) == 'yes';
79            $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
80        }
81
82        $tableClass = 'cargoTable';
83        if ( $mergeSimilarCells ) {
84            $tableClass .= ' mergeSimilarCells';
85        } else {
86            $tableClass .= ' noMerge sortable';
87        }
88
89        $text = "<table class=\"$tableClass\">";
90        $text .= '<thead><tr>';
91        foreach ( array_keys( $fieldDescriptions ) as $field ) {
92            if ( strpos( $field, 'Blank value ' ) === false ) {
93                // We add a class to enable special CSS and/or
94                // JS handling.
95                $className = 'field_' . str_replace( ' ', '_', $field );
96                $text .= Html::rawElement( 'th', [ 'class' => $className ], $field ) . "\n";
97            }
98        }
99        $text .= "</tr></thead>\n<tbody>";
100
101        if ( $mergeSimilarCells ) {
102            [ $duplicateValuesInTable, $blankedCells ] = $this->getHelperDataForMerging( $formattedValuesTable );
103        }
104
105        $columnIsOdd = [];
106
107        foreach ( $formattedValuesTable as $rowNum => $row ) {
108            $text .= "<tr>\n";
109            foreach ( array_keys( $fieldDescriptions ) as $field ) {
110                if (
111                    $mergeSimilarCells &&
112                    array_key_exists( $rowNum, $blankedCells ) &&
113                    in_array( $field, $blankedCells[$rowNum] )
114                ) {
115                    continue;
116                }
117
118                if ( !array_key_exists( $field, $columnIsOdd ) ) {
119                    $columnIsOdd[$field] = true;
120                }
121
122                // Add a unique class to enable special CSS
123                // and/or JS handling.
124                $className = 'field_' . str_replace( ' ', '_', $field );
125
126                if ( $mergeSimilarCells ) {
127                    // If there are merged cells, we can't
128                    // use the standard "nth-child" CSS
129                    // approach, so add a class to indicate
130                    // whether this is an odd or even row.
131                    if ( $columnIsOdd[$field] ) {
132                        $className .= ' odd';
133                        $columnIsOdd[$field] = false;
134                    } else {
135                        $className .= ' even';
136                        $columnIsOdd[$field] = true;
137                    }
138                }
139
140                $attrs = [ 'class' => $className ];
141                if (
142                    $mergeSimilarCells &&
143                    array_key_exists( $rowNum, $duplicateValuesInTable ) &&
144                    array_key_exists( $field, $duplicateValuesInTable[$rowNum] )
145                ) {
146                    $attrs['rowspan'] = $duplicateValuesInTable[$rowNum][$field];
147                }
148
149                if ( array_key_exists( $field, $row ) ) {
150                    $value = $row[$field];
151                    if ( $fieldDescriptions[$field]->isDateOrDatetime() ) {
152                        $attrs['data-sort-value'] = $valuesTable[$rowNum][$field];
153                    }
154                } else {
155                    $value = null;
156                }
157
158                $valueText = $value == null ? '' : $value;
159
160                // Cargo reuses the "Page" system message of the main namespace
161                $pageMsg = wfMessage( "nstab-main" )->text();
162                if ( ( $field == "Page" || $field == $pageMsg || $field == '_pageName' ) &&
163                $editLink ) {
164                    $rawValue = $valuesTable[$rowNum][$field];
165                    $title = Title::newFromText( $rawValue );
166                    if ( $title === null ) {
167                        continue;
168                    }
169                    $link = CargoUtils::makeLink(
170                        $linkRenderer, $title, wfMessage( 'editold' ), [], [ 'action' => 'edit', ]
171                    );
172                    $valueText .= ' (' . $link . ')';
173                }
174
175                $text .= Html::rawElement( 'td', $attrs, $valueText ) . "\n";
176            }
177            $text .= "</tr>\n";
178        }
179        $text .= "</tbody></table>";
180        return $text;
181    }
182
183}