├── .gitmodules ├── .editorconfig ├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── contributors.yml ├── SimpleMathJax.php ├── LICENSE ├── extension.json ├── SimpleMathJaxHooks.php ├── resources └── ext.SimpleMathJax.js └── README.md /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "resources/MathJax"] 2 | path = resources/MathJax 3 | url = https://github.com/mathjax/MathJax.git 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | #### Which issue this PR fixes / What this PR does / Why we need it 2 | 3 | 4 | 5 | - fixes # 6 | 7 | 8 | #### Checklist 9 | 10 | - [ ] `extension.json` version bumped 11 | 12 | 13 | -------------------------------------------------------------------------------- /SimpleMathJax.php: -------------------------------------------------------------------------------- 1 | and ", 7 | "license-name": "GPL-2.0+", 8 | "type": "parserhook", 9 | "AutoloadClasses": { 10 | "SimpleMathJaxHooks": "SimpleMathJaxHooks.php" 11 | }, 12 | "config": { 13 | "SmjUseCdn": {"value":true, "description":"true to load mathjax from CDN"}, 14 | "SmjUseChem": {"value":true, "description":"true to enabled chem tag"}, 15 | "SmjDisplayMath": {"value":[], "description":"MathJax.tex.displayMath"}, 16 | "SmjExtraInlineMath": {"value":[], "description":"MathJax.tex.inlineMath"}, 17 | "SmjIgnoreHtmlClass": {"value":"mathjax_ignore|comment|diff-(context|addedline|deletedline)", "description":"MathJax.options.ignoreHtmlClass"}, 18 | "SmjScale": {"value":1, "description":"MathJax.chtml.scale"}, 19 | "SmjEnableMenu": {"value":true, "description":"MathJax.options.enableMenu"}, 20 | "SmjDisplayAlign": {"value":"left", "description":"MathJax.chtml.displayAlign"}, 21 | "SmjWrapDisplaystyle": {"value":true, "description":"true to wrap with displaystyle"}, 22 | "SmjEnableHtmlAttributes": {"value":false, "description":"true to process attributes of math tag"} 23 | }, 24 | "Hooks": { 25 | "ParserFirstCallInit": "SimpleMathJaxHooks::onParserFirstCallInit" 26 | }, 27 | "ResourceModules": { 28 | "ext.SimpleMathJax": { 29 | "scripts": ["resources/ext.SimpleMathJax.js"], 30 | "targets": ["desktop", "mobile"] 31 | } 32 | }, 33 | "ResourceFileModulePaths": { 34 | "localBasePath": "", 35 | "remoteExtPath": "SimpleMathJax" 36 | }, 37 | "manifest_version": 2 38 | } 39 | -------------------------------------------------------------------------------- /SimpleMathJaxHooks.php: -------------------------------------------------------------------------------- 1 | addJsConfigVars( 'wgSmjUseCdn', $wgSmjUseCdn ); 11 | $wgOut->addJsConfigVars( 'wgSmjUseChem', $wgSmjUseChem ); 12 | $wgOut->addJsConfigVars( 'wgSmjDisplayMath', $wgSmjDisplayMath ); 13 | $wgOut->addJsConfigVars( 'wgSmjExtraInlineMath', $wgSmjExtraInlineMath ); 14 | $wgOut->addJsConfigVars( 'wgSmjIgnoreHtmlClass', $wgSmjIgnoreHtmlClass ); 15 | $wgOut->addJsConfigVars( 'wgSmjScale', $wgSmjScale ); 16 | $wgOut->addJsConfigVars( 'wgSmjEnableMenu', $wgSmjEnableMenu ); 17 | $wgOut->addJsConfigVars( 'wgSmjDisplayAlign', $wgSmjDisplayAlign ); 18 | $wgOut->addJsConfigVars( 'wgSmjEnableHtmlAttributes', $wgSmjEnableHtmlAttributes ); 19 | $wgOut->addModules( [ 'ext.SimpleMathJax' ] ); 20 | $wgOut->addModules( [ 'ext.SimpleMathJax.mobile' ] ); // For MobileFrontend 21 | 22 | $parser->setHook( 'math', __CLASS__ . '::renderMath' ); 23 | if( $wgSmjUseChem ) $parser->setHook( 'chem', __CLASS__ . '::renderChem' ); } 24 | 25 | public static function renderMath($tex, array $args, Parser $parser, PPFrame $frame ) { 26 | global $wgSmjWrapDisplaystyle, $wgSmjEnableHtmlAttributes; 27 | 28 | if( !$wgSmjEnableHtmlAttributes ) $args = []; 29 | if( !isset($args["chem"]) ) { 30 | $tex = str_replace('\>', '\;', $tex); 31 | $tex = str_replace('<', '\lt ', $tex); 32 | $tex = str_replace('>', '\gt ', $tex); 33 | } 34 | if( !isset($args["display"]) ) { 35 | if( $wgSmjWrapDisplaystyle ) $tex = "\\displaystyle{ $tex }"; 36 | } else switch ($args["display"]) { 37 | case "": 38 | break; 39 | case "inline": 40 | $tex = "\\textstyle{ $tex }"; 41 | break; 42 | case "block": 43 | $tex = "\\displaystyle{ $tex }"; 44 | break; 45 | default: 46 | return self::renderError('SimpleMathJax: Invalid attribute value: display="' . $args["display"] . '"'); 47 | } 48 | return self::renderTex($tex, $parser, $args); 49 | } 50 | 51 | public static function renderChem($tex, array $args, Parser $parser, PPFrame $frame ) { 52 | global $wgSmjEnableHtmlAttributes; 53 | 54 | if( !$wgSmjEnableHtmlAttributes ) $args = []; 55 | return self::renderTex("\\ce{ $tex }", $parser, $args); 56 | } 57 | 58 | private static function renderTex($tex, $parser, $args) { 59 | global $wgSmjEnableHtmlAttributes; 60 | 61 | $hookContainer = MediaWiki\MediaWikiServices::getInstance()->getHookContainer(); 62 | $attributes = [ "style" => "opacity:.5" ]; 63 | $attributes["class"] = ($args["class"] ?? ''); 64 | if( !$wgSmjEnableHtmlAttributes ) { 65 | $attributes["class"] .= " smj-container"; 66 | } 67 | $inherit_tags = [ "id", "title", "lang", "dir" ]; 68 | foreach( $inherit_tags as $tag ) { 69 | if( isset($args[$tag]) ) $attributes[$tag] = $args[$tag]; 70 | } 71 | $hookContainer->run( "SimpleMathJaxAttributes", [ &$attributes, $tex ] ); 72 | if( $wgSmjEnableHtmlAttributes && !isset($args["debug"]) ) { 73 | $attributes["class"] .= " smj-container"; 74 | } 75 | 76 | if( isset($args["display"]) && $args["display"] == "block" ) { 77 | $element = Html::Element( "span", $attributes, "\\begin{displaymjx}{$tex}\\end{displaymjx}" ); 78 | } else { 79 | $element = Html::Element( "span", $attributes, "[math]{$tex}[/math]" ); 80 | } 81 | return [$element, 'markerType'=>'nowiki']; 82 | } 83 | 84 | private static function renderError($str) { 85 | $attributes = [ "class" => "error texerror" ]; 86 | $element = Html::Element( "strong", $attributes, $str ); 87 | return [$element, 'markerType'=>'nowiki']; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /resources/ext.SimpleMathJax.js: -------------------------------------------------------------------------------- 1 | mw.hook( 'wikipage.content' ).add( function ( $content ) { 2 | window.MathJax = { 3 | tex: { 4 | inlineMath: mw.config.get('wgSmjExtraInlineMath').concat([['[math]','[/math]']]), 5 | displayMath: mw.config.get('wgSmjDisplayMath'), 6 | packages: mw.config.get('wgSmjUseChem') ? {'[+]': ['mhchem']} : {}, 7 | macros: { 8 | AA: "{\u00c5}", 9 | alef: "{\\aleph}", 10 | alefsym: "{\\aleph}", 11 | Alpha: "{\\mathrm{A}}", 12 | and: "{\\land}", 13 | ang: "{\\angle}", 14 | Bbb: "{\\mathbb}", 15 | Beta: "{\\mathrm{B}}", 16 | bold: "{\\mathbf}", 17 | bull: "{\\bullet}", 18 | C: "{\\mathbb{C}}", 19 | Chi: "{\\mathrm{X}}", 20 | clubs: "{\\clubsuit}", 21 | cnums: "{\\mathbb{C}}", 22 | Complex: "{\\mathbb{C}}", 23 | coppa: "{\u03D9}", 24 | Coppa: "{\u03D8}", 25 | Dagger: "{\\ddagger}", 26 | Digamma: "{\u03DC}", 27 | darr: "{\\downarrow}", 28 | dArr: "{\\Downarrow}", 29 | Darr: "{\\Downarrow}", 30 | dashint: "{\\unicodeInt{x2A0D}}", 31 | ddashint: "{\\unicodeInt{x2A0E}}", 32 | diamonds: "{\\diamondsuit}", 33 | empty: "{\\emptyset}", 34 | Epsilon: "{\\mathrm{E}}", 35 | Eta: "{\\mathrm{H}}", 36 | euro: "{\u20AC}", 37 | exist: "{\\exists}", 38 | geneuro: "{\u20AC}", 39 | geneuronarrow: "{\u20AC}", 40 | geneurowide: "{\u20AC}", 41 | H: "{\\mathbb{H}}", 42 | hAar: "{\\Leftrightarrow}", 43 | harr: "{\\leftrightarrow}", 44 | Harr: "{\\Leftrightarrow}", 45 | hearts: "{\\heartsuit}", 46 | image: "{\\Im}", 47 | infin: "{\\infty}", 48 | Iota: "{\\mathrm{I}}", 49 | isin: "{\\in}", 50 | Kappa: "{\\mathrm{K}}", 51 | koppa: "{\u03DF}", 52 | Koppa: "{\u03DE}", 53 | lang: "{\\langle}", 54 | larr: "{\\leftarrow}", 55 | Larr: "{\\Leftarrow}", 56 | lArr: "{\\Leftarrow}", 57 | lrarr: "{\\leftrightarrow}", 58 | Lrarr: "{\\Leftrightarrow}", 59 | lrArr: "{\\Leftrightarrow}", 60 | Mu: "{\\mathrm{M}}", 61 | N: "{\\mathbb{N}}", 62 | natnums: "{\\mathbb{N}}", 63 | Nu: "{\\mathrm{N}}", 64 | O: "{\\emptyset}", 65 | oiint: "{\\unicodeInt{x222F}}", 66 | oiiint: "{\\unicodeInt{x2230}}", 67 | ointctrclockwise: "{\\unicodeInt{x2233}}", 68 | officialeuro: "{\u20AC}", 69 | Omicron: "{\\mathrm{O}}", 70 | or: "{\\lor}", 71 | P: "{\u00B6}", 72 | pagecolor: ["",1], 73 | part: "{\\partial}", 74 | plusmn: "{\\pm}", 75 | Q: "{\\mathbb{Q}}", 76 | R: "{\\mathbb{R}}", 77 | rang: "{\\rangle}", 78 | rarr: "{\\rightarrow}", 79 | Rarr: "{\\Rightarrow}", 80 | rArr: "{\\Rightarrow}", 81 | real: "{\\Re}", 82 | reals: "{\\mathbb{R}}", 83 | Reals: "{\\mathbb{R}}", 84 | Rho: "{\\mathrm{P}}", 85 | sdot: "{\\cdot}", 86 | sampi: "{\u03E1}", 87 | Sampi: "{\u03E0}", 88 | sect: "{\\S}", 89 | spades: "{\\spadesuit}", 90 | stigma: "{\u03DB}", 91 | Stigma: "{\u03DA}", 92 | sub: "{\\subset}", 93 | sube: "{\\subseteq}", 94 | supe: "{\\supseteq}", 95 | Tau: "{\\mathrm{T}}", 96 | textvisiblespace: "{\u2423}", 97 | thetasym: "{\\vartheta}", 98 | uarr: "{\\uparrow}", 99 | uArr: "{\\Uparrow}", 100 | Uarr: "{\\Uparrow}", 101 | unicodeInt: ["{\\mathop{\\vcenter{\\mathchoice{\\huge\\unicode{#1}\\,}{\\unicode{#1}}{\\unicode{#1}}{\\unicode{#1}}}\\,}\\nolimits}", 1], 102 | varcoppa: "{\u03D9}", 103 | varstigma: "{\u03DB}", 104 | varointclockwise: "{\\unicodeInt{x2232}}", 105 | vline: ["{\\smash{\\large\\lvert #1}", 0], 106 | weierp: "{\\wp}", 107 | Z: "{\\mathbb{Z}}", 108 | Zeta: "{\\mathrm{Z}}" 109 | }, 110 | environments: { 111 | displaymjx: ["", ""] 112 | } 113 | }, 114 | options: { 115 | ignoreHtmlClass: mw.config.get('wgSmjIgnoreHtmlClass'), 116 | processHtmlClass: mw.config.get('wgSmjEnableHtmlAttributes') ? "mathjax_process|smj-container" : "mathjax_process" 117 | }, 118 | chtml: { 119 | scale: mw.config.get('wgSmjScale'), 120 | displayAlign: mw.config.get('wgSmjDisplayAlign') 121 | }, 122 | loader: { 123 | load: mw.config.get('wgSmjUseChem') ? ['[tex]/mhchem'] : [] 124 | }, 125 | startup: { 126 | pageReady: () => { 127 | return MathJax.startup.defaultPageReady().then(() => { 128 | $(mw.config.get('wgSmjEnableHtmlAttributes') ? "span.smj-container > .MathJax" : ".MathJax").parent().css('opacity',1); 129 | }); 130 | } 131 | } 132 | }; 133 | (function () { 134 | var script = document.createElement('script'); 135 | script.src = mw.config.get('wgSmjUseCdn') 136 | ? 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js' 137 | : mw.config.get('wgExtensionAssetsPath') + '/SimpleMathJax/resources/MathJax/es5/tex-chtml.js'; 138 | script.async = true; 139 | document.head.appendChild(script); 140 | })(); 141 | }); 142 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The SimpleMathJax extension enables MathJax, a Javascript library, for typesetting TeX formula in MediaWiki inside math environments. 2 | 3 | https://www.mediawiki.org/wiki/Extension:SimpleMathJax 4 | 5 | 6 | # Installation 7 | * git clone in extensions directory 8 | * Using CDN is recommended. Because it's much faster than using local resources in most cases. ("the benefits of using a CDN") 9 | ```Bash 10 | $ git clone https://github.com/jmnote/SimpleMathJax.git 11 | ``` 12 | 13 | * (Optional) If you want to use not CDN but local mathjax scripts, you can use git clone recursive. 14 | ```Bash 15 | $ git clone --recursive https://github.com/jmnote/SimpleMathJax.git 16 | ``` 17 | 18 | * LocalSettings.php 19 | ```PHP 20 | wfLoadExtension( 'SimpleMathJax' ); 21 | ``` 22 | 23 | # Optional Settings 24 | | Setting name | Description | default value | custom value example | 25 | | ------------------------ | -------------------------------- | ------------------------- | --------------------------- | 26 | | `$wgSmjUseCdn` | use CDN or local scripts | true | false | 27 | | `$wgSmjUseChem` | enable chem tag | true | false | 28 | | `$wgSmjEnableMenu` | MathJax.options.enableMenu | true | false | 29 | | `$wgSmjDisplayMath` | MathJax.tex.displayMath | [] | [['$$','$$'],['\\[','\\]']] | 30 | | `$wgSmjExtraInlineMath` | MathJax.tex.inlineMath | [] | [['\\(', '\\)']] | 31 | | `$wgSmjIgnoreHtmlClass` | MathJax.options.ignoreHtmlClass | "mathjax_ignore\|comment\|
diff-(context\|
addedline\|deletedline)" | "mathjax_ignore" | 32 | | `$wgSmjScale` | MathJax.chtml.scale | 1 | 1.5 | 33 | | `$wgSmjDisplayAlign` | MathJax.chtml.displayAlign | "center" | "left" | 34 | | `$wgSmjWrapDisplaystyle` | wrap with displaystyle on `` | true | false | 35 | | `$wgSmjEnableHtmlAttributes` | process attributes of math tag | false | true | 36 | 37 | If you want to change font size, set `$wgSmjScale`. 38 | ```PHP 39 | wfLoadExtension( 'SimpleMathJax' ); 40 | $wgSmjScale = 1.5; 41 | ``` 42 | 43 | If you want to use local module, set `$wgSmjUseCdn`. 44 | ```PHP 45 | wfLoadExtension( 'SimpleMathJax' ); 46 | $wgSmjUseCdn = false; 47 | ``` 48 | 49 | If you want to enable some extra inlineMath symbol pairs, set `$wgSmjExtraInlineMath`. Pairs of `[math][/math]` are always in-line math delimiters. (And independently of this setting, you can use `$ ... $` to switch to math mode within chemical formulas in the mhchem extension.) 50 | ```PHP 51 | wfLoadExtension( 'SimpleMathJax' ); 52 | $wgSmjExtraInlineMath = [["$","$"],["\\(","\\)"]]; 53 | ``` 54 | 55 | Since version 0.8.7, inlineMath and blockMath and environments are ignored in edit summaries and diffs. To restore the previous behavior (especially if you are using maths in edit summaries), set `$wgSmjIgnoreHtmlClass`. 56 | ```PHP 57 | wfLoadExtension( 'SimpleMathJax' ); 58 | $wgSmjIgnoreHtmlClass = "mathjax_ignore"; 59 | ``` 60 | 61 | If you want to disable MathJax context menu, set `$wgSmjEnableMenu`. 62 | ```PHP 63 | wfLoadExtension( 'SimpleMathJax' ); 64 | $wgSmjEnableMenu = false; 65 | ``` 66 | 67 | Since version 0.8.8, by enabling `$wgSmjEnableHtmlAttributes`, the `display` attribute of the `` tag will work, and the `class` and `id` attributes of the `` tag will be carried over to the `` tag. 68 | ```PHP 69 | wfLoadExtension( 'SimpleMathJax' ); 70 | $wgSmjEnableHtmlAttributes = true; 71 | ``` 72 | 73 | # Hooks 74 | The hook `SimpleMathJaxAttributes` is available to add attributes to the span around the math. (Note that this process is performed only for `` elements, and other delimiters are handled directly by MathJax.) This hook provides you with the opportunity to ensure that your own code does not interfere with MathJax's rendering of math. 75 | 76 | For instance, if Lingo's JS functions are called before MathJax is invoked, then it is possible that Lingo will change the text so that MathJax could no longer render the math. 77 | 78 | Lingo understands that [it should not touch anything inside an element with the class `noglossary`](https://www.mediawiki.org/wiki/Extension:Lingo#Excluding_text_from_markup) so the following code can be used to keep Lingo from ruining math: 79 | ```PHP 80 | $wgHooks['SimpleMathJaxAttributes'][] 81 | = function ( array &$attributes, string $tex ) { 82 | $attributes['class'] .= ' noglossary'; 83 | }; 84 | ``` 85 | 86 | ## Contributors 87 | 88 | 89 | 90 | 91 | 92 | 99 | 106 | 113 | 120 | 127 | 134 | 135 | 136 | 143 | 150 | 157 | 164 | 171 | 178 | 179 | 180 | 187 | 194 | 201 | 208 | 215 | 222 | 223 | 224 |
93 | 94 | jmnote 95 |
96 | jmnote 97 |
98 |
100 | 101 | jamesmontalvo3 102 |
103 | James Montalvo 104 |
105 |
107 | 108 | hexmode 109 |
110 | Mark A. Hershberger 111 |
112 |
114 | 115 | dummy-index 116 |
117 | dummy-index 118 |
119 |
121 | 122 | lakejason0 123 |
124 | lakejason0 125 |
126 |
128 | 129 | badshah400 130 |
131 | Atri Bhattacharya 132 |
133 |
137 | 138 | Nikerabbit 139 |
140 | Niklas Laxström 141 |
142 |
144 | 145 | cubercsl 146 |
147 | cubercsl 148 |
149 |
151 | 152 | liberaldev 153 |
154 | Liberal Dev 155 |
156 |
158 | 159 | Adnn 160 |
161 | Adnn 162 |
163 |
165 | 166 | dexgs 167 |
168 | Dexter Gaon-Shatford 169 |
170 |
172 | 173 | pastakhov 174 |
175 | Pavel Astakhov 176 |
177 |
181 | 182 | v-gar 183 |
184 | Viktor Garske 185 |
186 |
188 | 189 | rickselby 190 |
191 | Rick Selby 192 |
193 |
195 | 196 | guyru 197 |
198 | guyru 199 |
200 |
202 | 203 | poiega 204 |
205 | poiega 206 |
207 |
209 | 210 | vedmaka 211 |
212 | Vedmaka 213 |
214 |
216 | 217 | yardenac 218 |
219 | Yardena Cohen 220 |
221 |
225 | 226 | --------------------------------------------------------------------------------