Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 78 |
|
0.00% |
0 / 8 |
CRAP | |
0.00% |
0 / 1 |
CheckMatrixWidget | |
0.00% |
0 / 78 |
|
0.00% |
0 / 8 |
342 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
12 | |||
getTableRow | |
0.00% |
0 / 22 |
|
0.00% |
0 / 1 |
30 | |||
getCellTag | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
isTagChecked | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
isTagDisabled | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
getTooltip | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getJavaScriptClassName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getConfig | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Widget; |
4 | |
5 | use OOUI\CheckboxInputWidget; |
6 | use OOUI\FieldLayout; |
7 | use OOUI\HtmlSnippet; |
8 | use OOUI\Tag; |
9 | use OOUI\Widget; |
10 | |
11 | /** |
12 | * Check matrix widget. Displays a matrix of checkboxes for given options |
13 | * |
14 | * @copyright 2018 MediaWiki Widgets Team and others; see AUTHORS.txt |
15 | * @license MIT |
16 | */ |
17 | class CheckMatrixWidget extends Widget { |
18 | /** @var string|null */ |
19 | protected $name; |
20 | /** @var string|null */ |
21 | protected $id; |
22 | /** @var array */ |
23 | protected $columns; |
24 | /** @var array */ |
25 | protected $rows; |
26 | /** @var array */ |
27 | protected $tooltips; |
28 | /** @var array */ |
29 | protected $tooltipsHtml; |
30 | /** @var array */ |
31 | protected $values; |
32 | /** @var array */ |
33 | protected $forcedOn; |
34 | /** @var array */ |
35 | protected $forcedOff; |
36 | |
37 | /** |
38 | * Operates similarly to MultiSelectWidget, but instead of using an array of |
39 | * options, uses an array of rows and an array of columns to dynamically |
40 | * construct a matrix of options. The tags used to identify a particular cell |
41 | * are of the form "columnName-rowName" |
42 | * |
43 | * @param array $config Configuration array with the following options: |
44 | * - columns |
45 | * - Required associative array mapping column labels (as HTML) to their tags. |
46 | * - rows |
47 | * - Required associative array mapping row labels (as HTML) to their tags. |
48 | * - force-options-on |
49 | * - Array of column-row tags to be displayed as enabled but unavailable to change. |
50 | * - force-options-off |
51 | * - Array of column-row tags to be displayed as disabled but unavailable to change. |
52 | * - tooltips |
53 | * - Optional associative array mapping row labels to tooltips (as text, will be escaped). |
54 | * - tooltips-html |
55 | * - Optional associative array mapping row labels to tooltips (as HTML). Takes precedence |
56 | * over text tooltips. |
57 | */ |
58 | public function __construct( array $config = [] ) { |
59 | // Configuration initialization |
60 | |
61 | parent::__construct( $config ); |
62 | |
63 | $this->name = $config['name'] ?? null; |
64 | $this->id = $config['id'] ?? null; |
65 | |
66 | // Properties |
67 | $this->rows = $config['rows'] ?? []; |
68 | $this->columns = $config['columns'] ?? []; |
69 | $this->tooltips = $config['tooltips'] ?? []; |
70 | $this->tooltipsHtml = $config['tooltips-html'] ?? []; |
71 | |
72 | $this->values = $config['values'] ?? []; |
73 | |
74 | $this->forcedOn = $config['forcedOn'] ?? []; |
75 | $this->forcedOff = $config['forcedOff'] ?? []; |
76 | |
77 | // Build the table |
78 | $table = new Tag( 'table' ); |
79 | $table->addClasses( [ 'mw-htmlform-matrix mw-widget-checkMatrixWidget-matrix' ] ); |
80 | $thead = new Tag( 'thead' ); |
81 | $table->appendContent( $thead ); |
82 | $tr = new Tag( 'tr' ); |
83 | |
84 | // Build the header |
85 | $tr->appendContent( $this->getCellTag( "\u{00A0}" ) ); |
86 | foreach ( $this->columns as $columnLabel => $columnTag ) { |
87 | $tr->appendContent( |
88 | $this->getCellTag( new HtmlSnippet( $columnLabel ), 'th' ) |
89 | ); |
90 | } |
91 | $thead->appendContent( $tr ); |
92 | |
93 | // Build the options matrix |
94 | $tbody = new Tag( 'tbody' ); |
95 | $table->appendContent( $tbody ); |
96 | foreach ( $this->rows as $rowLabel => $rowTag ) { |
97 | $tbody->appendContent( |
98 | $this->getTableRow( $rowLabel, $rowTag ) |
99 | ); |
100 | } |
101 | |
102 | // Initialization |
103 | $this->addClasses( [ 'mw-widget-checkMatrixWidget' ] ); |
104 | $this->appendContent( $table ); |
105 | } |
106 | |
107 | /** |
108 | * Get a formatted table row for the option, with |
109 | * a checkbox widget. |
110 | * |
111 | * @param string $label Row label (as HTML) |
112 | * @param string $tag Row tag name |
113 | * |
114 | * @return Tag The resulting table row |
115 | */ |
116 | private function getTableRow( $label, $tag ) { |
117 | $row = new Tag( 'tr' ); |
118 | $tooltip = $this->getTooltip( $label ); |
119 | $labelFieldConfig = $tooltip ? [ 'help' => $tooltip ] : []; |
120 | // Build label cell |
121 | $labelField = new FieldLayout( |
122 | new Widget(), // Empty widget, since we don't have the checkboxes here |
123 | [ |
124 | 'label' => new HtmlSnippet( $label ), |
125 | 'align' => 'inline', |
126 | ] + $labelFieldConfig |
127 | ); |
128 | $row->appendContent( $this->getCellTag( $labelField ) ); |
129 | |
130 | // Build checkbox column cells |
131 | foreach ( $this->columns as $columnTag ) { |
132 | $thisTag = "$columnTag-$tag"; |
133 | |
134 | // Construct a checkbox |
135 | $checkbox = new CheckboxInputWidget( [ |
136 | 'value' => $thisTag, |
137 | 'name' => $this->name ? "{$this->name}[]" : null, |
138 | 'id' => $this->id ? "{$this->id}-$thisTag" : null, |
139 | 'selected' => $this->isTagChecked( $thisTag ), |
140 | 'disabled' => $this->isTagDisabled( $thisTag ), |
141 | ] ); |
142 | |
143 | $row->appendContent( $this->getCellTag( $checkbox ) ); |
144 | } |
145 | return $row; |
146 | } |
147 | |
148 | /** |
149 | * Get an individual cell tag with requested content |
150 | * |
151 | * @param mixed $content Content for the <td> cell |
152 | * @param string $tagElement |
153 | * @return Tag Resulting cell |
154 | */ |
155 | private function getCellTag( $content, $tagElement = 'td' ) { |
156 | $cell = new Tag( $tagElement ); |
157 | $cell->appendContent( $content ); |
158 | return $cell; |
159 | } |
160 | |
161 | /** |
162 | * Check whether the given tag's checkbox should |
163 | * be checked |
164 | * |
165 | * @param string $tagName |
166 | * @return bool Tag should be checked |
167 | */ |
168 | private function isTagChecked( $tagName ) { |
169 | // If the tag is in the value list |
170 | return in_array( $tagName, (array)$this->values, true ) || |
171 | // Or if the tag is forced on |
172 | in_array( $tagName, (array)$this->forcedOn, true ); |
173 | } |
174 | |
175 | /** |
176 | * Check whether the given tag's checkbox should |
177 | * be disabled |
178 | * |
179 | * @param string $tagName |
180 | * @return bool Tag should be disabled |
181 | */ |
182 | private function isTagDisabled( $tagName ) { |
183 | return ( |
184 | // If the entire widget is disabled |
185 | $this->isDisabled() || |
186 | // If the tag is 'forced on' or 'forced off' |
187 | in_array( $tagName, (array)$this->forcedOn, true ) || |
188 | in_array( $tagName, (array)$this->forcedOff, true ) |
189 | ); |
190 | } |
191 | |
192 | /** |
193 | * Get the tooltip help associated with this row |
194 | * |
195 | * @param string $label Label name |
196 | * |
197 | * @return string Tooltip. Null if none is available. |
198 | */ |
199 | private function getTooltip( $label ) { |
200 | if ( isset( $this->tooltipsHtml[ $label ] ) ) { |
201 | return new HtmlSnippet( $this->tooltipsHtml[ $label ] ); |
202 | } else { |
203 | return $this->tooltips[ $label ] ?? null; |
204 | } |
205 | } |
206 | |
207 | protected function getJavaScriptClassName() { |
208 | return 'mw.widgets.CheckMatrixWidget'; |
209 | } |
210 | |
211 | public function getConfig( &$config ) { |
212 | $config += [ |
213 | 'name' => $this->name, |
214 | 'id' => $this->id, |
215 | 'rows' => $this->rows, |
216 | 'columns' => $this->columns, |
217 | 'tooltips' => $this->tooltips, |
218 | 'tooltipsHtml' => $this->tooltipsHtml, |
219 | 'forcedOff' => $this->forcedOff, |
220 | 'forcedOn' => $this->forcedOn, |
221 | 'values' => $this->values, |
222 | ]; |
223 | return parent::getConfig( $config ); |
224 | } |
225 | } |