2011-04-09 00:39:40 +00:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* MediaWiki math extension
|
|
|
|
*
|
2014-05-20 10:37:44 +00:00
|
|
|
* (c) 2002-2014 various MediaWiki contributors
|
2011-04-09 00:39:40 +00:00
|
|
|
* GPLv2 license; info in main package.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class MathHooks {
|
2014-01-02 17:18:51 +00:00
|
|
|
const mathCacheKey = 'math=';
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Generate a user dependent hash cache key.
|
|
|
|
* The hash key depends on the rendering mode.
|
|
|
|
* @param &$confstr The to-be-hashed key string that is being constructed
|
|
|
|
* @param User $user reference to the current user
|
|
|
|
* @param array &$forOptions userOptions used on that page
|
|
|
|
*/
|
|
|
|
public static function onPageRenderingHash( &$confstr, $user = false, &$forOptions = array() ) {
|
|
|
|
global $wgUser;
|
|
|
|
|
|
|
|
// To be independent of the MediaWiki core version,
|
|
|
|
// we check if the core caching logic for math is still available.
|
2014-02-09 19:02:15 +00:00
|
|
|
if ( ! is_callable( 'ParserOptions::getMath' ) && in_array( 'math', $forOptions ) ) {
|
2014-01-02 17:18:51 +00:00
|
|
|
if ( $user === false ) {
|
|
|
|
$user = $wgUser;
|
|
|
|
}
|
|
|
|
|
|
|
|
$mathOption = $user->getOption( 'math' );
|
|
|
|
// Check if the key already contains the math option part
|
|
|
|
if (
|
|
|
|
!preg_match(
|
|
|
|
'/(^|!)' . self::mathCacheKey . $mathOption . '(!|$)/',
|
|
|
|
$confstr
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
// The math part of cache key starts with "math=" followed by a star or a number for the math mode
|
|
|
|
// and the optional letter j that indicates if clientside MathJax rendering is used.
|
2014-02-09 19:02:15 +00:00
|
|
|
if ( preg_match( '/(^|!)' . self::mathCacheKey . '[*\d]m?(!|$)/', $confstr ) ) {
|
2014-01-02 17:18:51 +00:00
|
|
|
$confstr = preg_replace(
|
|
|
|
'/(^|!)' . self::mathCacheKey . '[*\d]m?(!|$)/',
|
|
|
|
'\1' . self::mathCacheKey . $mathOption . '\2',
|
|
|
|
$confstr
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
$confstr .= '!' . self::mathCacheKey . $mathOption;
|
|
|
|
}
|
|
|
|
|
|
|
|
wfDebugLog( 'Math', "New cache key: $confstr" );
|
|
|
|
} else {
|
|
|
|
wfDebugLog( 'Math', "Cache key found $confstr" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-04-09 15:13:22 +00:00
|
|
|
/**
|
2014-01-02 17:18:51 +00:00
|
|
|
* Set up $wgMathPath and $wgMathDirectory globals if they're not already set.
|
2011-04-09 15:13:22 +00:00
|
|
|
*/
|
2011-04-09 00:39:40 +00:00
|
|
|
static function setup() {
|
2014-01-02 17:18:51 +00:00
|
|
|
global $wgMathPath, $wgMathDirectory,
|
|
|
|
$wgUploadPath, $wgUploadDirectory;
|
|
|
|
|
2011-04-09 15:13:22 +00:00
|
|
|
if ( $wgMathPath === false ) {
|
|
|
|
$wgMathPath = "{$wgUploadPath}/math";
|
|
|
|
}
|
2014-01-02 17:18:51 +00:00
|
|
|
|
2011-04-09 15:13:22 +00:00
|
|
|
if ( $wgMathDirectory === false ) {
|
|
|
|
$wgMathDirectory = "{$wgUploadDirectory}/math";
|
|
|
|
}
|
2011-04-09 00:39:40 +00:00
|
|
|
}
|
|
|
|
|
2011-04-09 15:13:22 +00:00
|
|
|
/**
|
|
|
|
* Register the <math> tag with the Parser.
|
|
|
|
*
|
2011-07-17 21:11:24 +00:00
|
|
|
* @param $parser Parser instance of Parser
|
2011-04-09 15:13:22 +00:00
|
|
|
* @return Boolean: true
|
|
|
|
*/
|
|
|
|
static function onParserFirstCallInit( $parser ) {
|
2011-04-09 00:39:40 +00:00
|
|
|
$parser->setHook( 'math', array( 'MathHooks', 'mathTagHook' ) );
|
2014-01-02 17:18:51 +00:00
|
|
|
|
2011-04-09 00:39:40 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-04-09 15:13:22 +00:00
|
|
|
* Callback function for the <math> parser hook.
|
|
|
|
*
|
2012-10-27 14:30:50 +00:00
|
|
|
* @param $content (the LaTeX input)
|
2011-04-09 15:13:22 +00:00
|
|
|
* @param $attributes
|
2014-01-02 17:18:51 +00:00
|
|
|
* @param Parser $parser
|
2014-02-03 23:22:26 +00:00
|
|
|
* @return array
|
2011-04-09 00:39:40 +00:00
|
|
|
*/
|
|
|
|
static function mathTagHook( $content, $attributes, $parser ) {
|
2014-02-03 23:22:26 +00:00
|
|
|
global $wgUseMathJax, $wgMathDisableTexFilter;
|
2014-01-02 17:18:51 +00:00
|
|
|
|
|
|
|
if ( trim( $content ) === '' ) { // bug 8372
|
|
|
|
return '';
|
2012-10-27 14:30:50 +00:00
|
|
|
}
|
2014-01-02 17:18:51 +00:00
|
|
|
|
2013-11-18 10:45:43 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2014-01-02 17:18:51 +00:00
|
|
|
$mode = (int)$parser->getUser()->getOption( 'math' );
|
|
|
|
|
|
|
|
// Indicate that this page uses math.
|
|
|
|
// This affects the page caching behavior.
|
|
|
|
if ( is_callable( 'ParserOptions::getMath' ) ) {
|
|
|
|
$parser->getOptions()->getMath();
|
|
|
|
} else {
|
|
|
|
$parser->getOptions()->optionUsed( 'math' );
|
|
|
|
}
|
|
|
|
|
|
|
|
$renderer = MathRenderer::getRenderer( $content, $attributes, $mode );
|
2014-01-03 14:29:03 +00:00
|
|
|
|
|
|
|
if ( !$wgMathDisableTexFilter ) {
|
|
|
|
$checkResult = $renderer->checkTex();
|
2014-01-02 17:18:51 +00:00
|
|
|
|
|
|
|
if ( $checkResult !== true ) {
|
|
|
|
// Returns the error message
|
2014-01-03 14:29:03 +00:00
|
|
|
return $renderer->getLastError();
|
|
|
|
}
|
|
|
|
}
|
2014-06-05 21:06:43 +00:00
|
|
|
if ( $renderer->render() ) {
|
|
|
|
wfDebugLog( "Math" , "Rendering successful. Writing output" );
|
|
|
|
$renderedMath = $renderer->getHtmlOutput();
|
|
|
|
} else {
|
|
|
|
wfDebugLog( "Math" , "Rendering failed. Printing error message." );
|
|
|
|
return $renderer->getLastError();
|
|
|
|
}
|
2014-07-12 22:19:28 +00:00
|
|
|
wfRunHooks( 'MathFormulaRendered',
|
|
|
|
array( &$renderer,
|
|
|
|
&$renderedMath,
|
|
|
|
$parser->getTitle()->getArticleID(),
|
|
|
|
$parser->nextLinkID() ) );// Enables indexing of math formula
|
2014-04-08 13:57:15 +00:00
|
|
|
if ( $wgUseMathJax ) {
|
2012-03-05 20:34:29 +00:00
|
|
|
$parser->getOutput()->addModules( array( 'ext.math.mathjax.enabler' ) );
|
2011-11-29 00:37:13 +00:00
|
|
|
}
|
2014-03-17 06:14:02 +00:00
|
|
|
$parser->getOutput()->addModuleStyles( array( 'ext.math.styles' ) );
|
2014-01-02 17:18:51 +00:00
|
|
|
|
2014-06-05 21:06:43 +00:00
|
|
|
// Writes cache if rendering was successful
|
2013-03-12 04:38:45 +00:00
|
|
|
$renderer->writeCache();
|
2013-11-18 10:45:43 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2014-01-02 17:18:51 +00:00
|
|
|
|
2014-02-03 23:22:26 +00:00
|
|
|
return array( $renderedMath, "markerType" => 'nowiki' );
|
2011-04-09 00:39:40 +00:00
|
|
|
}
|
|
|
|
|
2011-04-09 15:13:22 +00:00
|
|
|
/**
|
|
|
|
* Add the new math rendering options to Special:Preferences.
|
|
|
|
*
|
|
|
|
* @param $user Object: current User object
|
|
|
|
* @param $defaultPreferences Object: Preferences object
|
|
|
|
* @return Boolean: true
|
|
|
|
*/
|
2011-04-09 00:39:40 +00:00
|
|
|
static function onGetPreferences( $user, &$defaultPreferences ) {
|
2014-05-05 09:38:20 +00:00
|
|
|
global $wgUseMathJax, $wgMathValidModes, $wgDefaultUserOptions;
|
2011-04-09 00:39:40 +00:00
|
|
|
$defaultPreferences['math'] = array(
|
|
|
|
'type' => 'radio',
|
2012-10-04 12:11:36 +00:00
|
|
|
'options' => array_flip( self::getMathNames() ),
|
2011-04-09 00:39:40 +00:00
|
|
|
'label' => ' ',
|
|
|
|
'section' => 'rendering/math',
|
|
|
|
);
|
2014-04-08 13:57:15 +00:00
|
|
|
if ( $wgUseMathJax ) {
|
|
|
|
$defaultPreferences['mathJax'] = array(
|
|
|
|
'type' => 'toggle',
|
|
|
|
'label-message' => 'mw_math_mathjax',
|
|
|
|
'section' => 'rendering/math',
|
|
|
|
);
|
|
|
|
}
|
2014-05-05 09:38:20 +00:00
|
|
|
// If the default option is not in the valid options the
|
|
|
|
// user interface throws an exception (BUG 64844)
|
|
|
|
if ( ! in_array( $wgDefaultUserOptions['math'] , $wgMathValidModes ) ){
|
|
|
|
wfDebugLog( 'Math', "Warning: Misconfiguration \$wgDefaultUserOptions['math'] is not in \$wgMathValidModes. Please check your LocalSetting.php file.");
|
|
|
|
// Display the checkbox in the first option.
|
|
|
|
$wgDefaultUserOptions['math'] = $wgMathValidModes[0];
|
|
|
|
}
|
2011-04-09 00:39:40 +00:00
|
|
|
return true;
|
|
|
|
}
|
2011-04-09 19:57:35 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* List of message keys for the various math output settings.
|
|
|
|
*
|
|
|
|
* @return array of strings
|
|
|
|
*/
|
2014-05-28 18:12:39 +00:00
|
|
|
public static function getMathNames() {
|
2014-04-08 13:57:15 +00:00
|
|
|
global $wgMathValidModes;
|
|
|
|
$MathConstantNames = array(
|
|
|
|
MW_MATH_SOURCE => 'mw_math_source',
|
|
|
|
MW_MATH_PNG => 'mw_math_png',
|
|
|
|
MW_MATH_MATHML => 'mw_math_mathml',
|
2014-05-20 10:37:44 +00:00
|
|
|
MW_MATH_LATEXML => 'mw_math_latexml'
|
2011-04-09 19:57:35 +00:00
|
|
|
);
|
2014-04-08 13:57:15 +00:00
|
|
|
$names = array();
|
|
|
|
foreach ( $wgMathValidModes as $mode ) {
|
|
|
|
$names[$mode] = wfMessage( $MathConstantNames[$mode] )->escaped();
|
2013-05-14 21:49:06 +00:00
|
|
|
}
|
2014-01-02 17:18:51 +00:00
|
|
|
|
2012-03-05 20:34:29 +00:00
|
|
|
return $names;
|
2011-04-09 19:57:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* MaintenanceRefreshLinksInit handler; optimize settings for refreshLinks batch job.
|
|
|
|
*
|
|
|
|
* @param Maintenance $maint
|
|
|
|
* @return boolean hook return code
|
|
|
|
*/
|
|
|
|
static function onMaintenanceRefreshLinksInit( $maint ) {
|
|
|
|
global $wgUser;
|
|
|
|
|
2014-01-02 17:18:51 +00:00
|
|
|
# Don't generate TeX PNGs (the lack of a sensible current directory causes errors anyway)
|
2011-04-09 19:57:35 +00:00
|
|
|
$wgUser->setOption( 'math', MW_MATH_SOURCE );
|
2014-01-02 17:18:51 +00:00
|
|
|
|
2011-04-09 19:57:35 +00:00
|
|
|
return true;
|
|
|
|
}
|
2011-04-22 21:37:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* LoadExtensionSchemaUpdates handler; set up math table on install/upgrade.
|
|
|
|
*
|
2011-07-17 21:11:24 +00:00
|
|
|
* @param $updater DatabaseUpdater
|
2012-08-30 23:25:48 +00:00
|
|
|
* @throws MWException
|
2011-04-22 21:37:16 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
2011-06-07 17:33:34 +00:00
|
|
|
static function onLoadExtensionSchemaUpdates( $updater = null ) {
|
2014-05-21 10:16:15 +00:00
|
|
|
global $wgMathValidModes;
|
2012-10-27 14:30:50 +00:00
|
|
|
if ( is_null( $updater ) ) {
|
2014-01-02 17:18:51 +00:00
|
|
|
throw new MWException( 'Math extension is only necessary in 1.18 or above' );
|
2011-06-07 17:33:34 +00:00
|
|
|
}
|
2014-01-02 17:18:51 +00:00
|
|
|
|
2014-05-20 10:37:44 +00:00
|
|
|
$map = array( 'mysql', 'sqlite', 'postgres', 'oracle', 'mssql' );
|
2014-01-02 17:18:51 +00:00
|
|
|
|
2011-04-22 21:37:16 +00:00
|
|
|
$type = $updater->getDB()->getType();
|
2014-01-02 17:18:51 +00:00
|
|
|
|
2014-05-20 10:37:44 +00:00
|
|
|
if ( in_array( $type, $map ) ) {
|
2014-05-21 10:16:15 +00:00
|
|
|
$sql = dirname( __FILE__ ) . '/db/math.' . $type . '.sql';
|
|
|
|
$updater->addExtensionTable( 'math', $sql );
|
|
|
|
if ( in_array( MW_MATH_LATEXML, $wgMathValidModes ) ) {
|
|
|
|
if ( in_array( $type, array( 'mysql', 'sqlite', 'postgres' ) ) ) {
|
|
|
|
$sql = dirname( __FILE__ ) . '/db/mathlatexml.' . $type . '.sql';
|
|
|
|
$updater->addExtensionTable( 'mathlatexml', $sql );
|
|
|
|
} else {
|
|
|
|
throw new MWException( "Math extension does not currently support $type database for LaTeXML." );
|
|
|
|
}
|
|
|
|
}
|
2014-05-27 05:53:46 +00:00
|
|
|
if ( in_array( MW_MATH_MATHML, $wgMathValidModes ) ) {
|
|
|
|
if ( in_array( $type, array( 'mysql', 'sqlite', 'postgres' ) ) ) {
|
|
|
|
$sql = dirname( __FILE__ ) . '/db/mathoid.' . $type . '.sql';
|
|
|
|
$updater->addExtensionTable( 'mathoid', $sql );
|
|
|
|
} else {
|
|
|
|
throw new MWException( "Math extension does not currently support $type database for Mathoid." );
|
|
|
|
}
|
|
|
|
}
|
2011-04-22 21:37:16 +00:00
|
|
|
} else {
|
|
|
|
throw new MWException( "Math extension does not currently support $type database." );
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-05-21 10:16:15 +00:00
|
|
|
* Add 'math' and 'mathlatexml' tables to the list of tables that need to be copied to
|
2011-04-22 21:37:16 +00:00
|
|
|
* temporary tables for parser tests to run.
|
|
|
|
*
|
|
|
|
* @param array $tables
|
|
|
|
* @return bool
|
|
|
|
*/
|
2011-05-23 17:05:39 +00:00
|
|
|
static function onParserTestTables( &$tables ) {
|
2011-04-22 21:37:16 +00:00
|
|
|
$tables[] = 'math';
|
2014-05-21 10:16:15 +00:00
|
|
|
$tables[] = 'mathlatexml';
|
2011-04-22 21:37:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
2011-09-13 21:03:38 +00:00
|
|
|
|
2013-02-16 22:55:39 +00:00
|
|
|
/**
|
|
|
|
* Links to the unit test files for the test cases.
|
|
|
|
*
|
|
|
|
* @param string $files
|
|
|
|
* @return boolean (true)
|
|
|
|
*/
|
|
|
|
static function onRegisterUnitTests( &$files ) {
|
|
|
|
$testDir = __DIR__ . '/tests/';
|
|
|
|
$files = array_merge( $files, glob( "$testDir/*Test.php" ) );
|
2014-01-02 17:18:51 +00:00
|
|
|
|
2013-02-16 22:55:39 +00:00
|
|
|
return true;
|
|
|
|
}
|
2014-01-25 23:09:06 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @global type $wgOut
|
|
|
|
* @param type $toolbar
|
|
|
|
*/
|
|
|
|
static function onEditPageBeforeEditToolbar( &$toolbar ) {
|
|
|
|
global $wgOut;
|
|
|
|
$wgOut->addModules( array( 'ext.math.editbutton.enabler' ) );
|
|
|
|
}
|
2011-04-09 00:39:40 +00:00
|
|
|
}
|