2424import { PropertyList } from '../../Tree/Node.js' ;
2525import { AbstractMmlTokenNode , MmlNode , AttributeList , TEXCLASS } from '../MmlNode.js' ;
2626import { MmlMrow } from './mrow.js' ;
27- import { OperatorList , OPTABLE , RangeDef , RANGES } from '../OperatorDictionary.js' ;
27+ import { MmlMover , MmlMunder , MmlMunderover } from './munderover.js' ;
28+ import { OperatorList , OPTABLE , RangeDef , RANGES , MMLSPACING } from '../OperatorDictionary.js' ;
2829
2930/*****************************************************************/
3031/*
@@ -59,21 +60,10 @@ export class MmlMo extends AbstractMmlTokenNode {
5960 } ;
6061
6162 /*
62- * The sizes of the various lspace and rspace values in the operator table
63+ * Unicode ranges and their default TeX classes and MathML spacing
6364 */
64- public static SPACE = [
65- '0em' ,
66- '0.1111em' ,
67- '0.1667em' ,
68- '0.2222em' ,
69- '0.2667em' ,
70- '0.3333em'
71- ] ;
72-
73- /*
74- * Unicode ranges and their default TeX classes
75- */
76- public static RANGES : RangeDef [ ] = RANGES ;
65+ public static RANGES = RANGES ;
66+ public static MMLSPACING = MMLSPACING ;
7767
7868 /*
7969 * The Operator Dictionary.
@@ -85,6 +75,12 @@ export class MmlMo extends AbstractMmlTokenNode {
8575 */
8676 public texClass = TEXCLASS . REL ;
8777
78+ /*
79+ * The default MathML spacing on the left and right
80+ */
81+ public lspace = 5 / 18 ;
82+ public rspace = 5 / 18 ;
83+
8884 /*
8985 * @return {string } The mo kind
9086 */
@@ -138,15 +134,49 @@ export class MmlMo extends AbstractMmlTokenNode {
138134 return ( parent . isToken ? ( parent as AbstractMmlTokenNode ) . getText ( ) : '' ) ;
139135 }
140136
137+ /*
138+ * @override
139+ */
140+ public hasSpacingAttributes ( ) {
141+ return this . attributes . isSet ( 'lspace' ) ||
142+ this . attributes . isSet ( 'rspace' ) ;
143+ }
144+
145+ /*
146+ * @return {boolean } True is this mo is an accent in an munderover construction
147+ */
148+ get isAccent ( ) {
149+ let accent = false ;
150+ const node = this . coreParent ( ) ;
151+ if ( node ) {
152+ const key = ( node . isKind ( 'mover' ) ?
153+ ( ( node . childNodes [ ( node as MmlMover ) . over ] as MmlNode ) . coreMO ( ) ?
154+ 'accent' : '' ) :
155+ node . isKind ( 'munder' ) ?
156+ ( ( node . childNodes [ ( node as MmlMunder ) . under ] as MmlNode ) . coreMO ( ) ?
157+ 'accentunder' : '' ) :
158+ node . isKind ( 'munderover' ) ?
159+ ( this === ( node . childNodes [ ( node as MmlMunderover ) . over ] as MmlNode ) . coreMO ( ) ?
160+ 'accent' :
161+ this === ( node . childNodes [ ( node as MmlMunderover ) . under ] as MmlNode ) . coreMO ( ) ?
162+ 'accentunder' : '' ) :
163+ '' ) ;
164+ if ( key ) {
165+ const value = node . attributes . getExplicit ( key ) ;
166+ accent = ( value !== undefined ? accent : this . attributes . get ( 'accent' ) ) as boolean ;
167+ }
168+ }
169+ return accent ;
170+ }
171+
141172 /*
142173 * Produce the texClass based on the operator dictionary values
143174 *
144175 * @override
145176 */
146- public setTeXclass ( prev : MmlNode ) {
177+ public setTeXclass ( prev : MmlNode ) : MmlNode {
147178 let { form, lspace, rspace, fence} = this . attributes . getList ( 'form' , 'lspace' , 'rspace' , 'fence' ) as
148179 { form : string , lspace : string , rspace : string , fence : string } ;
149- // if (this.useMMLspacing) {this.texClass = TEXCLASS.NONE; return this}
150180 if ( fence && this . texClass === TEXCLASS . REL ) {
151181 if ( form === 'prefix' ) {
152182 this . texClass = TEXCLASS . OPEN ;
@@ -227,7 +257,7 @@ export class MmlMo extends AbstractMmlTokenNode {
227257 display : boolean = false , level : number = 0 , prime : boolean = false ) {
228258 super . setInheritedAttributes ( attributes , display , level , prime ) ;
229259 let mo = this . getText ( ) ;
230- let [ form1 , form2 , form3 ] = this . getForms ( ) ;
260+ let [ form1 , form2 , form3 ] = this . handleExplicitForm ( this . getForms ( ) ) ;
231261 this . attributes . setInherited ( 'form' , form1 ) ;
232262 let OPTABLE = ( this . constructor as typeof MmlMo ) . OPTABLE ;
233263 let def = OPTABLE [ form1 ] [ mo ] || OPTABLE [ form2 ] [ mo ] || OPTABLE [ form3 ] [ mo ] ;
@@ -236,10 +266,15 @@ export class MmlMo extends AbstractMmlTokenNode {
236266 for ( const name of Object . keys ( def [ 3 ] || { } ) ) {
237267 this . attributes . setInherited ( name , def [ 3 ] [ name ] ) ;
238268 }
269+ this . lspace = ( def [ 0 ] + 1 ) / 18 ;
270+ this . rspace = ( def [ 1 ] + 1 ) / 18 ;
239271 } else {
240272 let range = this . getRange ( mo ) ;
241273 if ( range ) {
242274 this . texClass = range [ 2 ] ;
275+ const spacing = ( this . constructor as typeof MmlMo ) . MMLSPACING [ range [ 2 ] ] ;
276+ this . lspace = ( spacing [ 0 ] + 1 ) / 18 ;
277+ this . rspace = ( spacing [ 1 ] + 1 ) / 18 ;
243278 }
244279 }
245280 }
@@ -269,6 +304,18 @@ export class MmlMo extends AbstractMmlTokenNode {
269304 return [ 'infix' , 'prefix' , 'postfix' ] ;
270305 }
271306
307+ /*
308+ * @param {string[] } forms The three forms in the default order they are to be tested
309+ * @return {string[] } The forms in the new order, if there is an explicit form attribute
310+ */
311+ protected handleExplicitForm ( forms : string [ ] ) {
312+ if ( this . attributes . isSet ( 'form' ) ) {
313+ const form = this . attributes . get ( 'form' ) as string ;
314+ forms = [ form ] . concat ( forms . filter ( name => ( name !== form ) ) ) ;
315+ }
316+ return forms ;
317+ }
318+
272319 /*
273320 * @param {string } mo The character to look up in the range table
274321 * @return {RangeDef } The unicode range in which the character falls, or null
0 commit comments