mmultiscripts.js (11768B)
1 /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 4 /************************************************************* 5 * 6 * MathJax/jax/output/CommonHTML/autoload/mmultiscripts.js 7 * 8 * Implements the CommonHTML output for <mmultiscripts> elements. 9 * 10 * --------------------------------------------------------------------- 11 * 12 * Copyright (c) 2015 The MathJax Consortium 13 * 14 * Licensed under the Apache License, Version 2.0 (the "License"); 15 * you may not use this file except in compliance with the License. 16 * You may obtain a copy of the License at 17 * 18 * http://www.apache.org/licenses/LICENSE-2.0 19 * 20 * Unless required by applicable law or agreed to in writing, software 21 * distributed under the License is distributed on an "AS IS" BASIS, 22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23 * See the License for the specific language governing permissions and 24 * limitations under the License. 25 */ 26 27 MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function () { 28 var VERSION = "2.6.0"; 29 var MML = MathJax.ElementJax.mml, 30 CHTML = MathJax.OutputJax.CommonHTML; 31 32 MML.mmultiscripts.Augment({ 33 toCommonHTML: function (node,stretch) { 34 if (!stretch) { 35 node = this.CHTMLcreateNode(node); 36 this.CHTMLhandleStyle(node); 37 this.CHTMLhandleScale(node); 38 this.CHTMLgetVariant(); 39 } 40 CHTML.BBOX.empty(this.CHTML); 41 42 // 43 // Get base node 44 // 45 var base, bbox; 46 if (stretch) { 47 base = CHTML.getNode(node,"mjx-base"); 48 } else { 49 this.CHTMLaddChild(node,0,{type:"mjx-base", noBBox:true, forceChild:true}); 50 base = node.firstChild; 51 } 52 bbox = this.CHTMLbboxFor(0); 53 if (bbox.ic) { 54 bbox.R -= bbox.ic; // remove IC (added by mo and mi) 55 if (!stretch) base.style.marginRight = CHTML.Em(-bbox.ic); 56 delta = 1.3*bbox.ic + .05; // make faked IC be closer to expeted results 57 } 58 59 // 60 // Collect scripts into horizontal boxes and add them into the node 61 // 62 var BOX = {}, BBOX = {}; 63 this.CHTMLgetScripts(BOX,BBOX,stretch,node); 64 var sub = BOX.sub, sup = BOX.sup, presub = BOX.presub, presup = BOX.presup; 65 var sbox = BBOX.sub, Sbox = BBOX.sup, pbox = BBOX.presub, Pbox = BBOX.presup; 66 if (!stretch) this.CHTMLaddBoxes(node,base,BOX); 67 68 // 69 // Get the initial values for the variables 70 // 71 var values = this.getValues("scriptlevel","scriptsizemultiplier"); 72 var sscale = (this.Get("scriptlevel") < 3 ? values.scriptsizemultiplier : 1); 73 var ex = CHTML.TEX.x_height, s = CHTML.TEX.scriptspace; 74 var q = CHTML.TEX.sup_drop * sscale, r = CHTML.TEX.sub_drop * sscale; 75 var u = bbox.h - q, v = bbox.d + r, delta = 0, p; 76 var bmml = this.data[this.base]; 77 if (bmml && (bmml.type === "mi" || bmml.type === "mo")) { 78 if (bmml.data.join("").length === 1 && bbox.rscale === 1 && !bbox.sH && 79 !bmml.Get("largeop")) {u = v = 0} 80 } 81 values = this.getValues("displaystyle","subscriptshift","superscriptshift","texprimestyle"); 82 values.subscriptshift = (values.subscriptshift === "" ? 0 : this.CHTMLlength2em(values.subscriptshift)); 83 values.superscriptshift = (values.superscriptshift === "" ? 0 : this.CHTMLlength2em(values.superscriptshift)); 84 85 var dx = (presub ? s+pbox.w : presup ? s+Pbox.w-delta : 0); 86 this.CHTML.combine(bbox,dx,0); var x = this.CHTML.w; 87 88 // 89 // Place the scripts as needed 90 // 91 if (!sup && !presup) { 92 v = Math.max(v,CHTML.TEX.sub1,values.subscriptshift); 93 if (sub) v = Math.max(v,sbox.h-(4/5)*ex); 94 if (presub) v = Math.max(v,pbox.h-(4/5)*ex); 95 if (sub) this.CHTMLplaceSubOnly(sub,sbox,x,v,s); 96 if (presub) this.CHTMLplacePresubOnly(presub,pbox,v,s); 97 } else { 98 if (!sub && !presub) { 99 p = CHTML.TEX[(values.displaystyle ? "sup1" : (values.texprimestyle ? "sup3" : "sup2"))]; 100 u = Math.max(u,p,values.superscriptshift); 101 if (sup) u = Math.max(u,Sbox.d+(1/4)*ex); 102 if (presup) u = Math.max(u,Pbox.d+(1/4)*ex); 103 if (sup) this.CHTMLplaceSupOnly(sup,Sbox,x,delta,u,s); 104 if (presup) this.CHTMLplacePresupOnly(presup,Pbox,delta,u,s); 105 } else { 106 v = Math.max(v,CHTML.TEX.sub2); 107 var t = CHTML.TEX.rule_thickness; 108 var h = (sbox||pbox).h, d = (Sbox||Pbox).d; 109 if (presub) h = Math.max(h,pbox.h); 110 if (presup) d = Math.max(d,Pbox.d); 111 if ((u - d) - (h - v) < 3*t) { 112 v = 3*t - u + d + h; q = (4/5)*ex - (u - d); 113 if (q > 0) {u += q; v -= q} 114 } 115 u = Math.max(u,values.superscriptshift); 116 v = Math.max(v,values.subscriptshift); 117 if (sup) { 118 if (sub) {this.CHTMLplaceSubSup(sub,sbox,sup,Sbox,x,delta,u,v,s)} 119 else {this.CHTMLplaceSupOnly(sup,Sbox,x,delta,u,s)} 120 } else if (sub) {this.CHTMLplaceSubOnly(sub,sbox,x,v,s)} 121 if (presup) { 122 if (presub) {this.CHTMLplacePresubPresup(presub,pbox,presup,Pbox,delta,u,v,s)} 123 else {this.CHTMLplacePresupOnly(presup,Pbox,delta,u,s)} 124 } else if (presub) {this.CHTMLplacePresubOnly(presub,pbox,v,s)} 125 } 126 } 127 this.CHTML.clean(); 128 this.CHTMLhandleSpace(node); 129 this.CHTMLhandleBBox(node); 130 this.CHTMLhandleColor(node); 131 return node; 132 }, 133 // 134 // Get the subscript, superscript, presubscript, and presuperscript 135 // boxes, with proper spacing, and computer their bounding boxes. 136 // 137 CHTMLgetScripts: function (BOX,BBOX,stretch,node) { 138 if (stretch) { 139 BOX.sub = CHTML.getNode(node,"mjx-sub"); 140 BOX.sup = CHTML.getNode(node,"mjx-sup"); 141 BOX.presub = CHTML.getNode(node,"mjx-presub"); 142 BOX.presup = CHTML.getNode(node,"mjx-presup"); 143 BBOX.sub = this.CHTMLbbox.sub; 144 BBOX.sup = this.CHTMLbbox.sup; 145 BBOX.presub = this.CHTMLbbox.presub; 146 BBOX.presup = this.CHTMLbbox.presup; 147 return; 148 } 149 this.CHTMLbbox = BBOX; // save for when stretched 150 var state = {i:1, w:0, BOX:BOX, BBOX:BBOX}, m = this.data.length; 151 var sub = "sub", sup = "sup"; 152 while (state.i < m) { 153 if ((this.data[state.i]||{}).type === "mprescripts") { 154 state.i++; state.w = 0; 155 sub = "presub"; sup = "presup"; 156 } else { 157 var sbox = this.CHTMLaddScript(sub,state); 158 var Sbox = this.CHTMLaddScript(sup,state); 159 var w = Math.max((sbox ? sbox.rscale*sbox.w : 0),(Sbox ? Sbox.rscale*Sbox.w : 0)); 160 this.CHTMLpadScript(sub,w,sbox,state); 161 this.CHTMLpadScript(sup,w,Sbox,state); 162 state.w += w; 163 } 164 } 165 if (BBOX.sub) BBOX.sub.clean(); 166 if (BBOX.sup) BBOX.sup.clean(); 167 if (BBOX.presub) BBOX.presub.clean(); 168 if (BBOX.presup) BBOX.presup.clean(); 169 }, 170 // 171 // Add a script to the proper box, creating the box if needed, 172 // and padding the box to account for any <none/> elements. 173 // Return the bounding box for the script for later use. 174 // 175 CHTMLaddScript: function (type,state) { 176 var BOX, BBOX, data = this.data[state.i]; 177 if (data && data.type !== "none" && data.type !== "mprescripts") { 178 BOX = state.BOX[type]; 179 if (!BOX) { 180 BOX = state.BOX[type] = CHTML.Element("mjx-"+type); 181 BBOX = state.BBOX[type] = CHTML.BBOX.empty(); 182 if (state.w) { 183 BOX.style.paddingLeft = CHTML.Em(state.w); 184 BBOX.w = BBOX.r = state.w; BBOX.x = state.w; 185 } 186 } 187 data.toCommonHTML(BOX); 188 BBOX = data.CHTML; 189 } 190 if (data && data.type !== "mprescripts") state.i++; 191 return BBOX; 192 }, 193 // 194 // Add padding to the script box to make match the width of the 195 // super- or subscript that is above or below it, and adjust the 196 // bounding box for the script row. If these are pre-scripts, 197 // right-justify the scripts, otherwise, left-justify them. 198 // 199 CHTMLpadScript: function (type,w,bbox,state) { 200 if (!bbox) bbox = {w:0, fake:1, rscale:1}; 201 var BBOX = state.BBOX[type], dx = 0, dw = 0; 202 if (BBOX) { 203 if (bbox.rscale*bbox.w < w) { 204 var BOX = state.BOX[type]; dw = w-bbox.rscale*bbox.w; 205 var space = CHTML.Element("mjx-spacer",{style:{width:CHTML.Em(dw)}}); 206 if (type.substr(0,3) === "pre" && !bbox.fake) { 207 BOX.insertBefore(space,BOX.lastChild); 208 dx = dw; dw = 0; 209 } else { 210 BOX.appendChild(space); 211 } 212 } 213 if (bbox.fake) {BBOX.w += dx} else {BBOX.combine(bbox,BBOX.w+dx,0)} 214 BBOX.w += dw; 215 } 216 }, 217 // 218 // Add the boxes into the main node, creating stacks when needed 219 // 220 CHTMLaddBoxes: function (node,base,BOX) { 221 var sub = BOX.sub, sup = BOX.sup, presub = BOX.presub, presup = BOX.presup; 222 if (presub && presup) { 223 var prestack = CHTML.Element("mjx-prestack"); node.insertBefore(prestack,base); 224 prestack.appendChild(presup); prestack.appendChild(presub); 225 } else { 226 if (presub) node.insertBefore(presub,base); 227 if (presup) node.insertBefore(presup,base); 228 } 229 if (sub && sup) { 230 var stack = CHTML.addElement(node,"mjx-stack"); 231 stack.appendChild(sup); stack.appendChild(sub); 232 } else { 233 if (sub) node.appendChild(sub); 234 if (sup) node.appendChild(sup); 235 } 236 }, 237 // 238 // Handle positioning the various scripts 239 // 240 CHTMLplaceSubOnly: function (sub,sbox,x,v,s) { 241 sub.style.verticalAlign = CHTML.Em(-v); 242 sub.style.marginRight = CHTML.Em(s); sbox.w += s; 243 this.CHTML.combine(sbox,x,-v); 244 }, 245 CHTMLplaceSupOnly: function (sup,Sbox,x,delta,u,s) { 246 sup.style.verticalAlign = CHTML.Em(u); 247 sup.style.paddingLeft = CHTML.Em(delta); 248 sup.style.paddingRight = CHTML.Em(s); Sbox.w += s; 249 this.CHTML.combine(Sbox,x+delta,u); 250 }, 251 CHTMLplaceSubSup: function (sub,sbox,sup,Sbox,x,delta,u,v,s) { 252 sub.style.paddingRight = CHTML.Em(s); sbox.w += s; 253 sup.style.paddingBottom = CHTML.Em(u+v-Sbox.d-sbox.h); 254 sup.style.paddingLeft = CHTML.Em(delta+(Sbox.x||0)); 255 sup.style.paddingRight = CHTML.Em(s); Sbox.w += s; 256 sup.parentNode.style.verticalAlign = CHTML.Em(-v); 257 this.CHTML.combine(sbox,x,-v); 258 this.CHTML.combine(Sbox,x+delta,u); 259 }, 260 CHTMLplacePresubOnly: function (presub,pbox,v,s) { 261 presub.style.verticalAlign = CHTML.Em(-v); 262 presub.style.marginLeft = CHTML.Em(s); 263 this.CHTML.combine(pbox,s,-v); 264 }, 265 CHTMLplacePresupOnly: function (presup,Pbox,delta,u,s) { 266 presup.style.verticalAlign = CHTML.Em(u); 267 presup.style.paddingLeft = CHTML.Em(s); 268 presup.style.paddingRight = CHTML.Em(-delta); 269 this.CHTML.combine(Pbox,s,u); 270 }, 271 CHTMLplacePresubPresup: function (presub,pbox,presup,Pbox,delta,u,v,s) { 272 presub.style.paddingLeft = CHTML.Em(s); 273 presup.style.paddingBottom = CHTML.Em(u+v-Pbox.d-pbox.h); 274 presup.style.paddingLeft = CHTML.Em(delta+s+(Pbox.x||0)); 275 presup.style.paddingRight = CHTML.Em(-delta); 276 presup.parentNode.style.verticalAlign = CHTML.Em(-v); 277 this.CHTML.combine(pbox,s,-v); 278 this.CHTML.combine(Pbox,s+delta,u); 279 }, 280 // 281 // Handle stretchy bases 282 // 283 CHTMLstretchH: MML.mbase.CHTMLstretchH, 284 CHTMLstretchV: MML.mbase.CHTMLstretchV 285 }); 286 287 MathJax.Hub.Startup.signal.Post("CommonHTML mmultiscripts Ready"); 288 MathJax.Ajax.loadComplete(CHTML.autoloadDir+"/mmultiscripts.js"); 289 }); 290