1<?php
2
3// must be run within Dokuwiki
4if(!defined('DOKU_INC')) die();
5
6require_once DOKU_PLUGIN . 'latexport/implementation/decorator.php';
7
8/**
9 * Adapts the mathjax expressions to latex.
10 * - If a $$ contains any \begin, then it is removed.
11 * - Transforms $$ into \begin{equation} and \end{equation}.
12 * - Groups multiple $$ into the same block of \begin{gather} \end{gather}.
13 * - Leaves inline equations surrounded by $$.
14 *
15 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
16 * @author Jean-Michel Gonet <jmgonet@yahoo.com>
17 */
18class DecoratorMath extends Decorator {
19
20	const NOT_IN_EQUATION    = 1000;
21	const IN_EQUATION        = 1001;
22
23	private $state;
24
25	private $equation;
26
27	/**
28	 * Class constructor.
29	 * @param archive Will receive the content of the document.
30	 */
31	function __construct($decorator) {
32		parent::__construct($decorator);
33		$this->state = DecoratorMath::NOT_IN_EQUATION;
34	}
35
36	/**
37	 * Receives mathematic formula from Mathjax plugin.
38	 * Sometimes a formula is split across several calls.
39	 * Formula is finished when any other command is called.
40	 */
41	function mathjax_content($formula) {
42		if ($this->state == DecoratorMath::NOT_IN_EQUATION) {
43			$this->equation = $formula;
44			$this->state = DecoratorMath::IN_EQUATION;
45		} else {
46			$this->equation = $this->equation.$formula;
47		}
48	}
49
50	/**
51	 * Sometimes a formula is split across several calls.
52	 * Formula is finished when any other command is called.
53	 */
54	function any_command() {
55		if ($this->state == DecoratorMath::IN_EQUATION) {
56			$this->decorator->mathjax_content($this->processEquation($this->equation));
57			$this->state = DecoratorMath::NOT_IN_EQUATION;
58		}
59	}
60
61	/**
62	 * Transforms the equation according to the rendering rules.
63	 * - Formula surrounded (inline) by $ ... $ is transformed to \( ... \)
64	 * - Formula surrounded by $$ ... $$ or \[ ... \] is surrounded with \begin{equation} ... \end{equation}
65	 * - Formula containing any amsmath command is left as is.
66	 * @param String $equation The equation.
67	 * @return String The escaped equation.
68	 */
69	private function processEquation($equation) {
70		if (substr( $equation, 0, 2 ) === "$$" || substr( $equation, 0, 2 ) === '\\[') {
71			return $this->processDisplayEquation($equation);
72		} else if (substr( $equation, 0, 1 ) === "$") {
73			return $this->processInlineEquation($equation);
74		} else {
75			return $this->processAmsMathEquation($equation);
76		}
77	}
78
79	private function processDisplayEquation($equation) {
80		$trimmedEquation = substr($equation, 2, strlen($equation) - 4);
81		$trimmedEquation = trim($trimmedEquation);
82		$trimmedEquation = $this->removeTagCommand($trimmedEquation);
83		return "\\begin{equation}\r\n    $trimmedEquation\r\n\\end{equation}\r\n";
84	}
85
86	private function processInlineEquation($equation) {
87		$trimmedEquation = trim($this->removeTagCommand($equation), '$ ');
88		return '\\('.$trimmedEquation.'\\)';
89	}
90
91	private function processAmsMathEquation($equation) {
92		return $equation;
93	}
94
95	/**
96	 * The tag command, although supported in Mathjax, it is not well handled by the 'equation'
97	 * environment.
98	 * @param String $equation The equation.
99	 * @return String The escaped equation.
100	 */
101	private function removeTagCommand($equation) {
102		return preg_replace('/\\\\tag\{[^}]+\}/', '', $equation);
103	}
104}
105