Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switching Between Text & Visual Editor Mangles MathML #43

Open
dac514 opened this issue Jun 10, 2019 · 3 comments
Open

Switching Between Text & Visual Editor Mangles MathML #43

dac514 opened this issue Jun 10, 2019 · 3 comments

Comments

@dac514
Copy link

dac514 commented Jun 10, 2019

Test equation:

<math>
<mrow>
  <mrow>
        <msup> <mi>x</mi> <mn>2</mn> </msup> <mo>+</mo>
            <mrow>
              <mn>4</mn>
              <mo>&InvisibleTimes;</mo>
              <mi>x</mi>
            </mrow>
    <mo>+</mo>
    <mn>4</mn>
  </mrow>
    <mo>=</mo>
    <mn>0</mn>
</mrow>
</math>

Works fine if there aren't any spaces:

<math><mrow><mrow><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><mrow><mn>4</mn><mo>&InvisibleTimes;</mo><mi>x</mi></mrow><mo>+</mo><mn>4</mn></mrow><mo>=</mo><mn>0</mn></mrow></math>

Steps to reproduce:

  1. Paste equation into Text Editor
  2. Switch to Visual Editor
  3. Switch back to text Editor

Expected:HTML not mangled
Actual: HTML Mangled

step1

step2

step3

@dac514
Copy link
Author

dac514 commented Jun 25, 2019

Switching between the visual and text editors breaks MathML tags
We can stop this from happening by forcing the MathML into one line without any returns
I've had some luck with the code snippet below.
I will do more testing and report back if there's anything unusual:

jQuery( document ).ready( function ( $ ) {
	$( 'body' ).bind( {
		// Switching between the visual and text editors breaks MathML tags
		// We can stop this from happening by forcing the MathML into one line without any returns
		beforeWpautop: ( e, o ) => {
			if ( o.unfiltered.indexOf( '</math>' ) !== -1 || o.unfiltered.indexOf( '</svg>' ) !== -1 ) {
				o.data = o.unfiltered.replace( /<(math|svg)[^>]*>[\s\S]*?<\/\1>/gi, match => {
					// Remove every white space between tags using JavaScript
					return match.replace( /(<(pre|script|style|textarea)[^]+?<\/\2)|(^|>)\s+|\s+(?=<|$)/g, '$1$3' );
				}
				);
			}
		},
	} );
} );

@dac514
Copy link
Author

dac514 commented Jun 28, 2019

PS: I also changed public static $mathml_tags to:

public function mathmlTags() {
	// Elements Common to Presentation and Content MathML
	// https://www.w3.org/TR/MathML3/appendixa.html#parsing.rnc.common
	$common_att = [ 'id', 'xref', 'class', 'style', 'href' ];
	$common_pres_att = [ 'mathcolor', 'mathbackground' ];
	$common_token_att = [ 'mathvariant', 'mathsize', 'dir' ];
	$def_enc_att = [ 'encoding', 'definitionURL' ];

	$mathml_tags = [
		// Presentation Markup (https://www.w3.org/TR/MathML3/chapter3.html)
		'annotation'     => array_merge( [ 'cd', 'name', 'src' ], $def_enc_att ),
		'annotation-xml' => array_merge( [ 'cd', 'name', 'src' ], $def_enc_att ),
		'maction'        => array_merge( [ 'actiontype', 'selection' ], $common_pres_att, $common_att ),
		'maligngroup'    => array_merge( [ 'groupalign' ], $common_pres_att, $common_att ),
		'malignmark'     => array_merge( [ 'edge' ], $common_pres_att, $common_att ),
		'math'           => array_merge( [ 'display', 'overflow', 'xmlns' ], $common_pres_att, $common_att ),
		'menclose'       => array_merge( [ 'notation' ], $common_pres_att, $common_att ),
		'merror'         => array_merge( $common_pres_att, $common_att ),
		'mfenced'        => array_merge( [ 'open', 'close', 'separators' ], $common_pres_att, $common_att ),
		'mfrac'          => array_merge( [ 'linethickness', 'numalign', 'denomalign', 'bevelled' ], $common_pres_att, $common_att ),
		'mglyph'         => array_merge( [ 'src', 'width', 'height', 'valign', 'alt', 'mathbackround' ], $common_att ),
		'mi'             => array_merge( $common_token_att, $common_pres_att, $common_att ),
		'mlabeledtr'     => array_merge( [ 'rowalign', 'columnalign', 'groupalign' ], $common_pres_att, $common_att ),
		'mlongdiv'       => array_merge( [ 'longdivstyle' ], $common_pres_att, $common_att ),
		'mmultiscripts'  => array_merge( [ 'subscriptshift', 'superscriptshift' ], $common_pres_att, $common_att ),
		'mn'             => array_merge( $common_token_att, $common_pres_att, $common_att ),
		'mo'             => array_merge( [ 'form', 'fence', 'separator', 'lspace', 'rspace', 'stretchy', 'symmetric', 'maxsize', 'minsize', 'largeop', 'movablelimits', 'accent' ], $common_token_att, $common_pres_att, $common_att ),
		'mover'          => array_merge( [ 'accent', 'align' ], $common_pres_att, $common_att ),
		'mpadded'        => array_merge( [ 'height', 'depth', 'width', 'lspace', 'voffset' ], $common_pres_att, $common_att ),
		'mphantom'       => array_merge( [ 'mathbackground' ], $common_att ),
		'mroot'          => array_merge( $common_pres_att, $common_att ),
		'mrow'           => array_merge( [ 'dir' ], $common_pres_att, $common_att ),
		'ms'             => array_merge( [ 'lquote', 'rquote' ], $common_token_att, $common_pres_att, $common_att ),
		'mscarries'      => array_merge( [ 'position', 'location', 'crossout', 'scriptsizemultiplier' ], $common_pres_att, $common_att ),
		'mscarry'        => array_merge( [ 'location', 'crossout' ], $common_pres_att, $common_att ),
		'msgroup'        => array_merge( [ 'position', 'shift' ], $common_pres_att, $common_att ),
		'msline'         => array_merge( [ 'position', 'length', 'leftoverhang', 'rightoverhang', 'mslinethickness' ], $common_pres_att, $common_att ),
		'mspace'         => array_merge( [ 'width', 'height', 'depth', 'linebreak' ], $common_pres_att, $common_att ),
		'msqrt'          => array_merge( $common_pres_att, $common_att ),
		'msrow'          => array_merge( [ 'position' ], $common_pres_att, $common_att ),
		'mstack'         => array_merge( [ 'align', 'stackalign', 'charalign', 'charspacing' ], $common_pres_att, $common_att ),
		'mstyle'         => array_merge( [ 'scriptlevel', 'displaystyle', 'scriptsizemultiplier', 'scriptminsize', 'infixlinebreakstyle', 'decimalpoint' ], $common_pres_att, $common_att ),
		'msub'           => array_merge( [ 'subscriptshift' ], $common_pres_att, $common_att ),
		'msubsup'        => array_merge( [ 'subscriptshift', 'superscriptshift' ], $common_pres_att, $common_att ),
		'msup'           => array_merge( [ 'superscriptshift' ], $common_pres_att, $common_att ),
		'mtable'         => array_merge( [ 'align', 'rowalign', 'columnalign', 'groupalign', 'alignmentscope', 'columnwidth', 'width', 'rowspacing', 'columnspacing', 'rowlines', 'columnlines', 'frame', 'framespacing', 'equalrows', 'equalcolumns', 'displaystyle', 'side', 'minlabelspacing' ], $common_pres_att, $common_att ),
		'mtd'            => array_merge( [ 'rowspan', 'columnspan', 'rowalign', 'columnalign', 'groupalign' ], $common_pres_att, $common_att ),
		'mtext'          => array_merge( $common_token_att, $common_pres_att, $common_att ),
		'mtr'            => array_merge( [ 'rowalign', 'columnalign', 'groupalign' ], $common_pres_att, $common_att ),
		'munder'         => array_merge( [ 'accentunder', 'align' ], $common_pres_att, $common_att ),
		'munderover'     => array_merge( [ 'accent', 'accentunder', 'align' ], $common_pres_att, $common_att ),
		'semantics'      => array_merge( [ 'cd', 'name', 'src' ], $def_enc_att ),
		// Content Markup (https://www.w3.org/TR/MathML3/chapter4.html)
		'abs'                 => array_merge( $common_att, $def_enc_att ),
		'and'                 => array_merge( $common_att, $def_enc_att ),
		'apply'               => array_merge( $common_att, $def_enc_att ),
		'approx'              => array_merge( $common_att, $def_enc_att ),
		'arccos'              => array_merge( $common_att, $def_enc_att ),
		'arccosh'             => array_merge( $common_att, $def_enc_att ),
		'arccot'              => array_merge( $common_att, $def_enc_att ),
		'arccoth'             => array_merge( $common_att, $def_enc_att ),
		'arccsc'              => array_merge( $common_att, $def_enc_att ),
		'arccsch'             => array_merge( $common_att, $def_enc_att ),
		'arcsec'              => array_merge( $common_att, $def_enc_att ),
		'arcsech'             => array_merge( $common_att, $def_enc_att ),
		'arcsin'              => array_merge( $common_att, $def_enc_att ),
		'arcsinh'             => array_merge( $common_att, $def_enc_att ),
		'arctan'              => array_merge( $common_att, $def_enc_att ),
		'arctanh'             => array_merge( $common_att, $def_enc_att ),
		'arg'                 => array_merge( $common_att, $def_enc_att ),
		'bind'                => array_merge( $common_att, $def_enc_att ),
		'bvar'                => array_merge( $common_att, $def_enc_att ),
		'card'                => array_merge( $common_att, $def_enc_att ),
		'cartesianproduct'    => array_merge( $common_att, $def_enc_att ),
		'ceiling'             => array_merge( $common_att, $def_enc_att ),
		'ci'                  => array_merge( [ 'type' ], $common_att, $def_enc_att ),
		'cn'                  => array_merge( [ 'type', 'base' ], $common_att, $def_enc_att ),
		'cs'                  => array_merge( $common_att, $def_enc_att ),
		'codomain'            => array_merge( $common_att, $def_enc_att ),
		'complexes'           => array_merge( $common_att, $def_enc_att ),
		'compose'             => array_merge( $common_att, $def_enc_att ),
		'condition'           => array_merge( $common_att, $def_enc_att ),
		'conjugate'           => array_merge( $common_att, $def_enc_att ),
		'cos'                 => array_merge( $common_att, $def_enc_att ),
		'cosh'                => array_merge( $common_att, $def_enc_att ),
		'cot'                 => array_merge( $common_att, $def_enc_att ),
		'coth'                => array_merge( $common_att, $def_enc_att ),
		'csc'                 => array_merge( $common_att, $def_enc_att ),
		'csch'                => array_merge( $common_att, $def_enc_att ),
		'csymbol'             => array_merge( [ 'type', 'cd' ], $common_att, $def_enc_att ),
		'curl'                => array_merge( $common_att, $def_enc_att ),
		'degree'              => $common_att,
		'determinant'         => array_merge( $common_att, $def_enc_att ),
		'diff'                => array_merge( $common_att, $def_enc_att ),
		'divergence'          => array_merge( $common_att, $def_enc_att ),
		'divide'              => array_merge( $common_att, $def_enc_att ),
		'domain'              => array_merge( $common_att, $def_enc_att ),
		'domainofapplication' => $common_att,
		'emptyset'            => array_merge( $common_att, $def_enc_att ),
		'eq'                  => array_merge( $common_att, $def_enc_att ),
		'equivalent'          => array_merge( $common_att, $def_enc_att ),
		'eulergamma'          => array_merge( $common_att, $def_enc_att ),
		'exists'              => array_merge( $common_att, $def_enc_att ),
		'exp'                 => array_merge( $common_att, $def_enc_att ),
		'exponentiale'        => array_merge( $common_att, $def_enc_att ),
		'factorial'           => array_merge( $common_att, $def_enc_att ),
		'factorof'            => array_merge( $common_att, $def_enc_att ),
		'false'               => array_merge( $common_att, $def_enc_att ),
		'floor'               => array_merge( $common_att, $def_enc_att ),
		'forall'              => array_merge( $common_att, $def_enc_att ),
		'gcd'                 => array_merge( $common_att, $def_enc_att ),
		'geq'                 => array_merge( $common_att, $def_enc_att ),
		'grad'                => array_merge( $common_att, $def_enc_att ),
		'gt'                  => array_merge( $common_att, $def_enc_att ),
		'ident'               => array_merge( $common_att, $def_enc_att ),
		'image'               => array_merge( $common_att, $def_enc_att ),
		'imaginary'           => array_merge( $common_att, $def_enc_att ),
		'imaginaryi'          => array_merge( $common_att, $def_enc_att ),
		'implies'             => array_merge( $common_att, $def_enc_att ),
		'in'                  => array_merge( $common_att, $def_enc_att ),
		'infinity'            => array_merge( $common_att, $def_enc_att ),
		'int'                 => array_merge( $common_att, $def_enc_att ),
		'integers'            => array_merge( $common_att, $def_enc_att ),
		'intersect'           => array_merge( $common_att, $def_enc_att ),
		'interval'            => array_merge( [ 'closure' ], $common_att, $def_enc_att ),
		'inverse'             => array_merge( $common_att, $def_enc_att ),
		'lambda'              => array_merge( $common_att, $def_enc_att ),
		'laplacian'           => array_merge( $common_att, $def_enc_att ),
		'lcm'                 => array_merge( $common_att, $def_enc_att ),
		'leq'                 => array_merge( $common_att, $def_enc_att ),
		'limit'               => array_merge( $common_att, $def_enc_att ),
		'list'                => array_merge( [ 'order' ], $common_att, $def_enc_att ),
		'ln'                  => array_merge( $common_att, $def_enc_att ),
		'log'                 => array_merge( $common_att, $def_enc_att ),
		'lowlimit'            => array_merge( $common_att, $def_enc_att ),
		'lt'                  => array_merge( $common_att, $def_enc_att ),
		'matrix'              => array_merge( $common_att, $def_enc_att ),
		'matrixrow'           => array_merge( $common_att, $def_enc_att ),
		'max'                 => array_merge( $common_att, $def_enc_att ),
		'mean'                => array_merge( $common_att, $def_enc_att ),
		'median'              => array_merge( $common_att, $def_enc_att ),
		'min'                 => array_merge( $common_att, $def_enc_att ),
		'minus'               => array_merge( $common_att, $def_enc_att ),
		'mode'                => array_merge( $common_att, $def_enc_att ),
		'moment'              => array_merge( $common_att, $def_enc_att ),
		'momentabout'         => array_merge( $common_att, $def_enc_att ),
		'naturalnumbers'      => array_merge( $common_att, $def_enc_att ),
		'neq'                 => array_merge( $common_att, $def_enc_att ),
		'not'                 => array_merge( $common_att, $def_enc_att ),
		'notanumber'          => array_merge( $common_att, $def_enc_att ),
		'notin'               => array_merge( $common_att, $def_enc_att ),
		'notprsubset'         => array_merge( $common_att, $def_enc_att ),
		'notsubset'           => array_merge( $common_att, $def_enc_att ),
		'or'                  => array_merge( $common_att, $def_enc_att ),
		'otherwise'           => array_merge( $common_att, $def_enc_att ),
		'outerproduct'        => array_merge( $common_att, $def_enc_att ),
		'partialdiff'         => array_merge( $common_att, $def_enc_att ),
		'pi'                  => array_merge( $common_att, $def_enc_att ),
		'piece'               => array_merge( $common_att, $def_enc_att ),
		'piecewise'           => array_merge( $common_att, $def_enc_att ),
		'plus'                => array_merge( $common_att, $def_enc_att ),
		'power'               => array_merge( $common_att, $def_enc_att ),
		'primes'              => array_merge( $common_att, $def_enc_att ),
		'product'             => array_merge( $common_att, $def_enc_att ),
		'prsubset'            => array_merge( $common_att, $def_enc_att ),
		'quotient'            => array_merge( $common_att, $def_enc_att ),
		'rationals'           => array_merge( $common_att, $def_enc_att ),
		'real'                => array_merge( $common_att, $def_enc_att ),
		'reals'               => array_merge( $common_att, $def_enc_att ),
		'rem'                 => array_merge( $common_att, $def_enc_att ),
		'root'                => array_merge( $common_att, $def_enc_att ),
		'scalarproduct'       => array_merge( $common_att, $def_enc_att ),
		'sdev'                => array_merge( $common_att, $def_enc_att ),
		'sec'                 => array_merge( $common_att, $def_enc_att ),
		'sech'                => array_merge( $common_att, $def_enc_att ),
		'selector'            => array_merge( $common_att, $def_enc_att ),
		'sep'                 => array_merge( $common_att, $def_enc_att ),
		'set'                 => array_merge( [ 'type' ], $common_att, $def_enc_att ),
		'setdiff'             => array_merge( $common_att, $def_enc_att ),
		'share'               => array_merge( [ 'src' ], $common_att ),
		'sin'                 => array_merge( $common_att, $def_enc_att ),
		'sinh'                => array_merge( $common_att, $def_enc_att ),
		'subset'              => array_merge( $common_att, $def_enc_att ),
		'sum'                 => array_merge( $common_att, $def_enc_att ),
		'tan'                 => array_merge( $common_att, $def_enc_att ),
		'tanh'                => array_merge( $common_att, $def_enc_att ),
		'tendsto'             => array_merge( [ 'type' ], $common_att, $def_enc_att ),
		'times'               => array_merge( $common_att, $def_enc_att ),
		'transpose'           => array_merge( $common_att, $def_enc_att ),
		'true'                => array_merge( $common_att, $def_enc_att ),
		'union'               => array_merge( $common_att, $def_enc_att ),
		'uplimit'             => array_merge( $common_att, $def_enc_att ),
		'variance'            => array_merge( $common_att, $def_enc_att ),
		'vector'              => array_merge( $common_att, $def_enc_att ),
		'vectorproduct'       => array_merge( $common_att, $def_enc_att ),
		'xor'                 => array_merge( $common_att, $def_enc_att ),
	];
	return $mathml_tags;
}

@paulschreiber
Copy link
Collaborator

@connerbw I think this is a bug in TinyMCE. I filed it there as well.

Please open a pull request to add support for additional MathML tags (per your code above).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants