Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 174 |
|
0.00% |
0 / 14 |
CRAP | |
0.00% |
0 / 1 |
FormulaInfo | |
0.00% |
0 / 174 |
|
0.00% |
0 / 14 |
1980 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
20 | |||
InfoTex | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
12 | |||
DisplayTranslations | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
20 | |||
GetTranslation | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
PrintTranslationResult | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 | |||
DisplayInfo | |
0.00% |
0 / 65 |
|
0.00% |
0 / 1 |
156 | |||
printSource | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
getlengh | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
formatBytes | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
hasMathMLSupport | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
hasSvgSupport | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
DisplayRendering | |
0.00% |
0 / 43 |
|
0.00% |
0 / 1 |
90 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | use MediaWiki\Extension\Math\MathConfig; |
4 | use MediaWiki\Extension\Math\MathRenderer; |
5 | use MediaWiki\MediaWikiServices; |
6 | |
7 | /** |
8 | * MediaWiki MathSearch extension |
9 | * |
10 | * (c) 2012 Moritz Schubotz |
11 | * GPLv2 license; info in main package. |
12 | * |
13 | * @file |
14 | * @ingroup extensions |
15 | */ |
16 | class FormulaInfo extends SpecialPage { |
17 | |
18 | /** @var bool */ |
19 | private $purge = false; |
20 | /** @var MathConfig */ |
21 | private $mathConfig; |
22 | |
23 | function __construct( |
24 | MathConfig $mathConfig |
25 | ) { |
26 | parent::__construct( 'FormulaInfo' ); |
27 | $this->mathConfig = $mathConfig; |
28 | } |
29 | |
30 | /** |
31 | * @param string|null $par |
32 | */ |
33 | function execute( $par ) { |
34 | $pid = $this->getRequest()->getVal( 'pid' ); // Page ID |
35 | $eid = $this->getRequest()->getVal( 'eid' ); // Equation ID |
36 | $this->purge = $this->getRequest()->getVal( 'purge', false ); |
37 | if ( $pid === null || $eid === null ) { |
38 | $tex = $this->getRequest()->getVal( 'tex', '' ); |
39 | if ( $tex == '' ) { |
40 | $this->getOutput()->addHTML( '<b>Please specify page and equation id</b>' ); |
41 | } else { |
42 | $this->InfoTex( $tex ); |
43 | } |
44 | } else { |
45 | $this->DisplayInfo( $pid, $eid ); |
46 | } |
47 | } |
48 | |
49 | public function InfoTex( $tex ) { |
50 | if ( !$this->getConfig()->get( 'MathDebug' ) ) { |
51 | $this->getOutput()->addWikiTextAsInterface( "tex queries only supported in debug mode" ); |
52 | return false; |
53 | } |
54 | $this->getOutput()->addWikiTextAsInterface( "Info for <code>" . $tex . '</code>' ); |
55 | |
56 | $mo = new MathObject( $tex ); |
57 | $allPages = $mo->getAllOccurrences(); |
58 | if ( $allPages ) { |
59 | $this->DisplayInfo( $allPages[0]->getRevisionID(), $allPages[0]->getAnchorID() ); |
60 | } else { |
61 | $this->getOutput()->addWikiTextAsInterface( |
62 | "No occurrences found clean up the database to remove unused formulae" |
63 | ); |
64 | } |
65 | |
66 | self::DisplayTranslations( $tex ); |
67 | } |
68 | |
69 | /** |
70 | * @param string $tex |
71 | * @return bool |
72 | */ |
73 | public static function DisplayTranslations( $tex ) { |
74 | global $wgOut, $wgMathSearchTranslationUrl; |
75 | |
76 | if ( $wgMathSearchTranslationUrl === false ) { |
77 | return false; |
78 | } |
79 | |
80 | $resultMaple = self::GetTranslation( 'Maple', $tex ); |
81 | $resultMathe = self::GetTranslation( 'Mathematica', $tex ); |
82 | |
83 | $wgOut->addWikiTextAsInterface( '==Translations to Computer Algebra Systems==' ); |
84 | |
85 | if ( $resultMaple === false || $resultMathe === false ) { |
86 | $wgOut->addWikiTextAsInterface( 'An error occurred during translation.' ); |
87 | return false; |
88 | } |
89 | |
90 | self::PrintTranslationResult( 'Maple', $resultMaple ); |
91 | self::PrintTranslationResult( 'Mathematica', $resultMathe ); |
92 | return true; |
93 | } |
94 | |
95 | private static function GetTranslation( $cas, $tex ) { |
96 | global $wgMathSearchTranslationUrl; |
97 | $params = [ 'cas' => $cas, 'latex' => $tex ]; |
98 | return MediaWikiServices::getInstance()->getHttpRequestFactory()->post( |
99 | $wgMathSearchTranslationUrl, [ "postData" => $params, "timeout" => 60 ] |
100 | ); |
101 | } |
102 | |
103 | private static function PrintTranslationResult( $cas, $result ) { |
104 | global $wgOut; |
105 | |
106 | $jsonResult = json_decode( $result, true ); |
107 | $wgOut->addWikiTextAsInterface( '=== Translation to ' . $cas . '===' ); |
108 | |
109 | $wgOut->addHTML( |
110 | '<div class="toccolours mw-collapsible mw-collapsed" style="text-align: left">' |
111 | ); |
112 | $wgOut->addWikiTextAsInterface( 'In ' . $cas . ': <code>' . $jsonResult['result'] . '</code>' ); |
113 | |
114 | $wgOut->addHTML( '<div class="mw-collapsible-content">' ); |
115 | $wgOut->addWikiTextAsInterface( str_replace( "\n", "\n\n", $jsonResult['log'] ) ); |
116 | $wgOut->addHTML( '</div></div>' ); |
117 | } |
118 | |
119 | public function DisplayInfo( int $oldID, string $eid ): bool { |
120 | $out = $this->getOutput(); |
121 | $out->addModuleStyles( [ 'ext.mathsearch.styles' ] ); |
122 | $out->addWikiTextAsInterface( '==General==' ); |
123 | $out->addWikiTextAsInterface( |
124 | 'Display information for equation id:' . $eid . ' on revision:' . $oldID |
125 | ); |
126 | $revisionRecord = MediaWikiServices::getInstance() |
127 | ->getRevisionLookup() |
128 | ->getRevisionById( $oldID ); |
129 | if ( !$revisionRecord ) { |
130 | $out->addWikiTextAsInterface( 'There is no revision with id:' . $oldID . ' in the database.' ); |
131 | return false; |
132 | } |
133 | |
134 | $title = Title::newFromLinkTarget( $revisionRecord->getPageAsLinkTarget() ); |
135 | $pageName = (string)$title; |
136 | $out->addWikiTextAsInterface( "* Page found: [[$pageName#$eid|$pageName]] (eq $eid) ", false ); |
137 | $link = $title->getLinkURL( [ |
138 | 'action' => 'purge', |
139 | 'mathpurge' => 'true' |
140 | ] ); |
141 | $out->addHTML( "<a href=\"$link\">(force rerendering)</a>" ); |
142 | $mo = MathObject::constructformpage( $oldID, $eid ); |
143 | if ( !$mo ) { |
144 | $out->addWikiTextAsInterface( 'Cannot find the equation data in the database.' . |
145 | ' Fetching from revision text.' ); |
146 | $mo = MathObject::newFromRevisionText( $oldID, $eid ); |
147 | } |
148 | $out->addWikiTextAsInterface( "Occurrences on the following pages:" ); |
149 | $all = $mo->getAllOccurrences(); |
150 | foreach ( $all as $occ ) { |
151 | $out->addWikiTextAsInterface( '*' . $occ->printLink2Page( false ) ); |
152 | } |
153 | $out->addWikiTextAsInterface( 'Hash: ' . $mo->getInputHash() ); |
154 | $this->printSource( $mo->getUserInputTex(), 'TeX (original user input)', 'latex' ); |
155 | $texInfo = $mo->getTexInfo(); |
156 | if ( $texInfo ) { |
157 | $this->printSource( $texInfo->getChecked(), 'TeX (checked)', 'latex' ); |
158 | } |
159 | $this->DisplayRendering( $mo->getUserInputTex(), 'latexml' ); |
160 | $this->DisplayRendering( $mo->getUserInputTex(), 'mathml' ); |
161 | $this->DisplayRendering( $mo->getUserInputTex(), 'native' ); |
162 | |
163 | self::DisplayTranslations( $mo->getUserInputTex() ); |
164 | |
165 | $out->addWikiTextAsInterface( '==Similar pages==' ); |
166 | $out->addWikiTextAsInterface( |
167 | 'Calculated based on the variables occurring on the entire ' . $pageName . ' page' |
168 | ); |
169 | $pid = $title->getArticleID(); |
170 | MathObject::findSimilarPages( $pid ); |
171 | $out->addWikiTextAsInterface( '==Identifiers==' ); |
172 | $relations = $mo->getRelations(); |
173 | if ( $texInfo ) { |
174 | foreach ( $texInfo->getIdentifiers() as $x ) { |
175 | $line = '* <math>' . $x . '</math>'; |
176 | if ( isset( $relations[$x] ) ) { |
177 | foreach ( $relations[$x] as $r ) { |
178 | $line .= ", {$r->definition} ($r->score)"; |
179 | } |
180 | } |
181 | $out->addWikiTextAsInterface( $line ); |
182 | } |
183 | } |
184 | $out->addWikiTextAsInterface( '=== MathML observations ===' ); |
185 | $mo->getObservations(); |
186 | if ( $this->getConfig()->get( 'MathDebug' ) ) { |
187 | $out->addWikiTextAsInterface( '==LOG and Debug==' ); |
188 | $this->printSource( $mo->getTimestamp(), 'Rendered at', 'text', false ); |
189 | $this->printSource( $mo->getIndexTimestamp(), 'and indexed at', 'text', false ); |
190 | $is_valid = $mo->getMathml() && $mo->isValidMathML( $mo->getMathml() ); |
191 | $this->printSource( $is_valid, 'validxml', 'text', false ); |
192 | $out->addHTML( $is_valid ? "valid" : "invalid" ); |
193 | $this->printSource( $mo->getStatusCode(), 'status' ); |
194 | $out->addHTML( htmlspecialchars( $mo->getLog() ) ); |
195 | } |
196 | return true; |
197 | } |
198 | |
199 | private function printSource( $source, $description = "", $language = "text", $linestart = true ) { |
200 | if ( $description ) { |
201 | $description .= ": "; |
202 | } |
203 | $this->getOutput()->addWikiTextAsInterface( "$description<syntaxhighlight lang=\"$language\">" . |
204 | $source . '</syntaxhighlight>', $linestart ); |
205 | } |
206 | |
207 | private static function getlengh( $binray ) { |
208 | $uncompressed = strlen( $binray ); |
209 | $compressed = strlen( gzcompress( $binray ) ); |
210 | return self::formatBytes( $uncompressed ) . " / " . self::formatBytes( $compressed ); |
211 | } |
212 | |
213 | private static function formatBytes( $bytes, $precision = 3 ) { |
214 | $units = [ 'B', 'KB', 'MB', 'GB', 'TB' ]; |
215 | |
216 | $bytes = max( $bytes, 0 ); |
217 | $pow = floor( ( $bytes ? log( $bytes ) : 0 ) / log( 1024 ) ); |
218 | $pow = min( $pow, count( $units ) - 1 ); |
219 | |
220 | // Uncomment one of the following alternatives |
221 | $bytes /= pow( 1024, $pow ); |
222 | // $bytes /= (1 << (10 * $pow)); |
223 | |
224 | return round( $bytes, $precision ) . ' ' . $units[$pow]; |
225 | } |
226 | |
227 | public static function hasMathMLSupport( $mode ) { |
228 | return in_array( $mode, [ 'latexml', 'mathml', 'native' ] ); |
229 | } |
230 | |
231 | public static function hasSvgSupport( $mode ) { |
232 | return ( $mode === 'latexml' || $mode === 'mathml' ); |
233 | } |
234 | |
235 | private function DisplayRendering( string $tex, string $mode ) { |
236 | if ( !in_array( $mode, $this->getConfig()->get( 'MathValidModes' ) ) ) { |
237 | return; |
238 | } |
239 | $out = $this->getOutput(); |
240 | $names = $this->mathConfig->getValidRenderingModeNames(); |
241 | $name = $names[$mode]; |
242 | $out->addWikiTextAsInterface( "=== $name rendering === " ); |
243 | $renderer = MathRenderer::getRenderer( $tex, [], $mode ); |
244 | if ( $this->purge ) { |
245 | $renderer->render( true ); |
246 | } elseif ( $mode == 'mathml' || !$renderer->isInDatabase() ) { |
247 | // workaround for restbase mathml mode that does not support database access |
248 | // $out->addWikiTextAsInterface( "No database entry. Start rendering" ); |
249 | $renderer->render(); |
250 | } |
251 | if ( self::hasMathMLSupport( $mode ) ) { |
252 | $out->addHTML( |
253 | '<div class="toccolours mw-collapsible mw-collapsed" style="text-align: left">' |
254 | ); |
255 | $out->addWikiTextAsInterface( |
256 | 'MathML (' . self::getlengh( $renderer->getMathml() ) . ') :', false |
257 | ); |
258 | $imgUrl = $this->getConfig()->get( 'ExtensionAssetsPath' ) . |
259 | '/MathSearch/resources/images/math_search_logo.png'; |
260 | $mathSearchImg = Html::element( |
261 | 'img', [ 'src' => $imgUrl, 'width' => 15, 'height' => 15 ] |
262 | ); |
263 | $out->addHTML( '<a href="/wiki/Special:MathSearch?mathpattern=' . urlencode( $tex ) . |
264 | '&searchx=Search">' . $mathSearchImg . '</a>' ); |
265 | $out->addHTML( $renderer->getMathml() ); |
266 | $out->addHTML( '<div class="mw-collapsible-content">' ); |
267 | $out->addWikiTextAsInterface( |
268 | '<syntaxhighlight lang="xml">' . ( $renderer->getMathml() ) . '</syntaxhighlight>' |
269 | ); |
270 | $out->addHTML( '</div></div>' ); |
271 | } |
272 | if ( self::hasSvgSupport( $mode ) ) { |
273 | try { |
274 | $svg = $renderer->getSvg( 'cached' ); |
275 | if ( $svg === '' ) { |
276 | $out->addWikiTextAsInterface( 'SVG image empty. Force Re-Rendering' ); |
277 | $renderer->render( true ); |
278 | $svg = $renderer->getSvg( 'render' ); |
279 | } |
280 | $out->addWikiTextAsInterface( 'SVG (' . self::getlengh( $svg ) . ') :', false ); |
281 | $out->addHTML( $svg ); // FALSE, 'mwe-math-demo' ) ); |
282 | $out->addHTML( "<br />\n" ); |
283 | } catch ( Exception $e ) { |
284 | $out->addHTML( 'Failed to get svg.' ); |
285 | } |
286 | } |
287 | $renderer->writeCache(); |
288 | } |
289 | |
290 | protected function getGroupName() { |
291 | return 'mathsearch'; |
292 | } |
293 | } |