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