Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 95 |
|
0.00% |
0 / 2 |
CRAP | |
0.00% |
0 / 1 |
JCTabularContentView | |
0.00% |
0 / 95 |
|
0.00% |
0 / 2 |
1560 | |
0.00% |
0 / 1 |
valueToHtml | |
0.00% |
0 / 90 |
|
0.00% |
0 / 1 |
1482 | |||
getDefault | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace JsonConfig; |
4 | |
5 | use MediaWiki\Html\Html; |
6 | use MediaWiki\MediaWikiServices; |
7 | use MediaWiki\Page\PageReference; |
8 | use MediaWiki\Parser\ParserOutput; |
9 | use ParserOptions; |
10 | |
11 | /** |
12 | * This class is used in case when there is no custom view defined for JCContent object |
13 | * @package JsonConfig |
14 | */ |
15 | class JCTabularContentView extends JCContentView { |
16 | |
17 | /** |
18 | * Render JCContent object as HTML |
19 | * Called from an override of AbstractContent::fillParserOutput() |
20 | * |
21 | * @param JCContent|JCTabularContent $content |
22 | * @param PageReference $page Context title for parsing |
23 | * @param int|null $revId Revision ID (for {{REVISIONID}}) |
24 | * @param ParserOptions $options Parser options |
25 | * @param bool $generateHtml Whether or not to generate HTML |
26 | * @param ParserOutput &$output The output object to fill (reference). |
27 | * @return string |
28 | */ |
29 | public function valueToHtml( |
30 | JCContent $content, PageReference $page, $revId, |
31 | ParserOptions $options, $generateHtml, ParserOutput &$output |
32 | ) { |
33 | // Use user's language, and split parser cache. This should not have a big |
34 | // impact because data namespace is rarely viewed, but viewing it localized |
35 | // will be valuable |
36 | $lang = $options->getUserLangObj(); |
37 | |
38 | $infoClass = [ 'class' => 'mw-tabular-value-info' ]; |
39 | $titleHeaders = []; |
40 | $nameHeaders = []; |
41 | $typeHeaders = []; |
42 | $rows = []; |
43 | $headerAttributes = []; |
44 | |
45 | // Helper to add a class value to an array of attributes |
46 | $addErr = static function ( array $attrs, $isValid ) { |
47 | if ( !$isValid ) { |
48 | $attrs['class'] = 'mw-tabular-error'; |
49 | } |
50 | return $attrs; |
51 | }; |
52 | |
53 | // Helper to create a <tr> element out of an array of raw HTML values |
54 | $makeRow = static function ( array $values, array $attrs = [] ) { |
55 | return Html::rawElement( 'tr', $attrs, implode( '', $values ) ); |
56 | }; |
57 | |
58 | $dataAttrs = [ 'class' => 'mw-tabular sortable' ]; |
59 | if ( !$content->getValidationData() || $content->getValidationData()->error() ) { |
60 | $dataAttrs['class'] .= ' mw-tabular-error'; |
61 | } |
62 | |
63 | $flds = $content->getField( [ 'schema', 'fields' ] ); |
64 | if ( $flds && !$flds->error() ) { |
65 | foreach ( $flds->getValue() as $fld ) { |
66 | $name = $content->getField( 'name', $fld ); |
67 | $nameIsValid = $name && !$name->error(); |
68 | $name = $nameIsValid ? $name->getValue() : ''; |
69 | |
70 | $title = $content->getField( 'title', $fld ); |
71 | $titleIsValid = $title && !$title->error(); |
72 | $title = |
73 | $titleIsValid ? JCUtils::pickLocalizedString( $title->getValue(), $lang, $name ) |
74 | : ''; |
75 | |
76 | $type = $content->getField( 'type', $fld ); |
77 | $typeIsValid = $type && !$type->error(); |
78 | $type = $typeIsValid ? $type->getValue() : ''; |
79 | |
80 | $thAttr = []; |
81 | if ( $nameIsValid ) { |
82 | $thAttr['data-name'] = $name; |
83 | } |
84 | if ( $typeIsValid ) { |
85 | $thAttr['data-type'] = $type; |
86 | $headerAttributes[] = [ 'data-type' => $type ]; |
87 | } else { |
88 | $headerAttributes[] = []; |
89 | } |
90 | |
91 | $nameHeaders[] = Html::element( 'th', $addErr( $thAttr, $nameIsValid ), $name ); |
92 | |
93 | $typeHeaders[] = |
94 | Html::element( 'th', $addErr( $thAttr, $typeIsValid ), |
95 | $typeIsValid ? wfMessage( 'jsonconfig-type-name-' . $type )->plain() : '' ); |
96 | |
97 | $titleHeaders[] = Html::element( 'th', $addErr( $thAttr, $titleIsValid ), $title ); |
98 | } |
99 | } |
100 | |
101 | $data = $content->getField( 'data' ); |
102 | if ( $data && !$data->error() ) { |
103 | foreach ( $data->getValue() as $row ) { |
104 | $rowIsValid = $row && $row instanceof JCValue && !$row->error(); |
105 | $row = ( $row && $row instanceof JCValue ) ? $row->getValue() : $row; |
106 | if ( !is_array( $row ) ) { |
107 | continue; |
108 | } |
109 | $vals = []; |
110 | foreach ( $row as $column ) { |
111 | $colIsValid = $column && $column instanceof JCValue && !$column->error(); |
112 | $column = |
113 | ( $column && $column instanceof JCValue ) ? $column->getValue() : $column; |
114 | |
115 | if ( count( $vals ) >= count( $headerAttributes ) ) { |
116 | $header = []; |
117 | } else { |
118 | $header = $headerAttributes[ count( $vals ) ]; |
119 | } |
120 | |
121 | if ( !$colIsValid ) { |
122 | $header['class'] = 'mw-tabular-error'; |
123 | } |
124 | |
125 | if ( is_object( $column ) ) { |
126 | $valueSize = count( (array)$column ); |
127 | $column = |
128 | htmlspecialchars( JCUtils::pickLocalizedString( $column, $lang ) ) . |
129 | Html::element( 'span', $infoClass, "($valueSize)" ); |
130 | } elseif ( is_bool( $column ) ) { |
131 | $column = $column ? '☑' : '☐'; |
132 | } elseif ( $column === null ) { |
133 | $header['class'] = 'mw-tabular-value-null'; |
134 | $column = ''; |
135 | } else { |
136 | $column = is_string( $column ) || is_numeric( $column ) |
137 | ? htmlspecialchars( (string)$column ) |
138 | : ''; |
139 | } |
140 | $vals[] = Html::rawElement( 'td', $header, $column ); |
141 | } |
142 | $rows[] = $makeRow( $vals, $rowIsValid ? [] : [ 'class' => 'mw-tabular-error' ] ); |
143 | } |
144 | } |
145 | |
146 | $html = |
147 | $content->renderDescription( $lang ) . |
148 | Html::rawElement( 'table', $dataAttrs, Html::rawElement( 'thead', [], implode( "\n", [ |
149 | $makeRow( $nameHeaders, [ 'class' => 'mw-tabular-row-key' ] ), |
150 | $makeRow( $typeHeaders, [ 'class' => 'mw-tabular-row-type' ] ), |
151 | $makeRow( $titleHeaders, [ 'class' => 'mw-tabular-row-name' ] ), |
152 | ] ) ) . Html::rawElement( 'tbody', [], implode( "\n", $rows ) ) ) . |
153 | $content->renderSources( |
154 | MediaWikiServices::getInstance()->getParserFactory()->getInstance(), |
155 | $page, |
156 | $revId, |
157 | $options |
158 | ) . $content->renderLicense(); |
159 | |
160 | return $html; |
161 | } |
162 | |
163 | /** |
164 | * Returns default content for this object |
165 | * @param string $modelId |
166 | * @return string |
167 | */ |
168 | public function getDefault( $modelId ) { |
169 | $licenseIntro = JCContentView::getLicenseIntro(); |
170 | |
171 | return <<<EOT |
172 | { |
173 | // !!!!! All comments will be automatically deleted on save !!!!! |
174 | |
175 | // Optional "description" field to describe this data |
176 | "description": {"en": "table description"}, |
177 | |
178 | // Optional "sources" field to describe the sources of the data. Can use Wiki Markup |
179 | "sources": "Copied from [http://example.com Example Data Source]", |
180 | |
181 | $licenseIntro |
182 | |
183 | // Mandatory fields schema. Each field must be an object with |
184 | // "name" being a valid identifier with consisting of letters, digits, and "_" |
185 | // "type" being one of the allowed types like "number", "string", "boolean", "localized" |
186 | "schema": { |
187 | "fields": [ |
188 | { |
189 | "name": "header1", |
190 | "type": "number", |
191 | // Optional label for this field |
192 | "title": {"en": "header 1"}, |
193 | }, |
194 | { |
195 | "name": "header2", |
196 | "type": "string", |
197 | // Optional label for this field |
198 | "title": {"en": "header 2"}, |
199 | } |
200 | ] |
201 | }, |
202 | |
203 | // array of data, with each row being an array of values |
204 | "data": [ |
205 | [ 42, "peace" ] |
206 | ] |
207 | } |
208 | EOT; |
209 | } |
210 | } |