mtable.js (22450B)
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/mtable.js 7 * 8 * Implements the CommonHTML output for <mtable> 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 CONFIG = MathJax.Hub.config, 31 CHTML = MathJax.OutputJax.CommonHTML, 32 SPLIT = MathJax.Hub.SplitList; 33 34 var LABEL = -1, 35 BIGDIMEN = 1000000; 36 37 MML.mtable.Augment({ 38 toCommonHTML: function (node) { 39 // 40 // Create the table nodes and put them in a table 41 // (so that its bottom is on the baseline, rather than aligned on the top row) 42 // 43 var state = {rows:[], labels:[], labeled: false}; 44 node = this.CHTMLdefaultNode(node,{noBBox:true, childOptions:state}); 45 var table = CHTML.Element("mjx-table"); 46 while (node.firstChild) table.appendChild(node.firstChild); 47 node.appendChild(table); 48 // 49 // Get the table attributes 50 // 51 var values = this.getValues("columnalign","rowalign","columnspacing","rowspacing", 52 "columnwidth","equalcolumns","equalrows", 53 "columnlines","rowlines","frame","framespacing", 54 "align","width","side","minlabelspacing","useHeight"); 55 var t = CHTML.TEX.min_rule_thickness/CHTML.em; 56 state.t = CHTML.Px(t*this.CHTML.scale,1); 57 // 58 // Create the table 59 // 60 this.CHTMLgetBoxSizes(values,state); 61 this.CHTMLgetAttributes(values,state); 62 if (values.equalrows) { 63 state.HD = true; 64 state.HH = Math.max.apply(Math,state.H); 65 state.DD = Math.max.apply(Math,state.D); 66 } 67 this.CHTMLadjustCells(values,state); 68 if (values.frame) table.style.border = state.t+" "+values.frame; 69 this.CHTMLalignV(values,state,node); 70 this.CHTMLcolumnWidths(values,state,node); 71 this.CHTMLstretchCells(values,state); 72 if (state.labeled) this.CHTMLaddLabels(values,state,node,table); 73 // 74 // Set the bounding box (ignores overlapping outside of the table) 75 // 76 var BBOX = this.CHTML; 77 BBOX.w = BBOX.r = state.R; 78 BBOX.h = BBOX.t = state.T-state.B; 79 BBOX.d = BBOX.b = state.B; 80 if (!values.frame && !BBOX.pwidth) { 81 node.style.padding = "0 "+CHTML.Em(1/6); 82 BBOX.L = BBOX.R = 1/6; 83 } 84 // 85 // Add any needed space and color 86 // 87 this.CHTMLhandleSpace(node); 88 this.CHTMLhandleBBox(node); 89 this.CHTMLhandleColor(node); 90 // 91 // Return the completed node 92 // 93 return node; 94 }, 95 // 96 // Get the natural height, depth, and widths of the rows and columns 97 // 98 CHTMLgetBoxSizes: function (values,state) { 99 var LH = CHTML.FONTDATA.lineH * values.useHeight, 100 LD = CHTML.FONTDATA.lineD * values.useHeight; 101 var H = [], D = [], W = [], J = -1; 102 for (var i = 0, m = this.data.length; i < m; i++) { 103 var row = this.data[i], s = (row.type === "mtr" ? 0 : LABEL); 104 H[i] = LH; D[i] = LD; 105 for (var j = s, M = row.data.length + s; j < M; j++) { 106 if (W[j] == null) {W[j] = -BIGDIMEN; if (j > J) J = j} 107 var cbox = row.data[j-s].CHTML; 108 if (cbox.h > H[i]) H[i] = cbox.h; 109 if (cbox.d > D[i]) D[i] = cbox.d; 110 if (cbox.w > W[j]) W[j] = cbox.w; 111 } 112 } 113 state.H = H; state.D = D; state.W = W, state.J = J; 114 }, 115 // 116 // Pad the spacing and alignment attributes to match the size of the table 117 // 118 CHTMLgetAttributes: function (values,state) { 119 var CSPACE = SPLIT(values.columnspacing), 120 RSPACE = SPLIT(values.rowspacing), 121 CALIGN = SPLIT(values.columnalign), 122 RALIGN = SPLIT(values.rowalign), 123 CLINES = SPLIT(values.columnlines), 124 RLINES = SPLIT(values.rowlines), 125 CWIDTH = SPLIT(values.columnwidth), 126 RCALIGN = [], i, m, J = state.J, M = state.rows.length-1; 127 for (i = 0, m = CSPACE.length; i < m; i++) CSPACE[i] = this.CHTMLlength2em(CSPACE[i]); 128 for (i = 0, m = RSPACE.length; i < m; i++) RSPACE[i] = this.CHTMLlength2em(RSPACE[i]); 129 while (CSPACE.length < J) CSPACE.push(CSPACE[CSPACE.length-1]); 130 while (CALIGN.length <= J) CALIGN.push(CALIGN[CALIGN.length-1]); 131 while (CLINES.length < J) CLINES.push(CLINES[CLINES.length-1]); 132 while (CWIDTH.length <= J) CWIDTH.push(CWIDTH[CWIDTH.length-1]); 133 while (RSPACE.length < M) RSPACE.push(RSPACE[RSPACE.length-1]); 134 while (RALIGN.length <= M) RALIGN.push(RALIGN[RALIGN.length-1]); 135 while (RLINES.length < M) RLINES.push(RLINES[RLINES.length-1]); 136 CALIGN[LABEL] = (values.side.substr(0,1) === "l" ? "left" : "right"); 137 // 138 // Override aligment data based on row-specific attributes 139 // 140 for (i = 0; i <= M; i++) { 141 var row = this.data[i]; RCALIGN[i] = []; 142 if (row.rowalign) RALIGN[i] = row.rowalign; 143 if (row.columnalign) { 144 RCALIGN[i] = SPLIT(row.columnalign); 145 while (RCALIGN[i].length <= J) RCALIGN[i].push(RCALIGN[i][RCALIGN[i].length-1]); 146 } 147 } 148 // 149 // Handle framespacing 150 // 151 var FSPACE = SPLIT(values.framespacing); 152 if (FSPACE.length != 2) FSPACE = SPLIT(this.defaults.framespacing); 153 FSPACE[0] = Math.max(0,this.CHTMLlength2em(FSPACE[0])); 154 FSPACE[1] = Math.max(0,this.CHTMLlength2em(FSPACE[1])); 155 if (values.columnlines.replace(/none/g,"").replace(/ /g,"") !== "" || 156 values.rowlines.replace(/none/g,"").replace(/ /g,"") !== "") values.fspace = true; 157 // 158 // Pad arrays so that final column can be treated as all the others 159 // 160 if (values.frame === MML.LINES.NONE) delete values.frame; else values.fspace = true; 161 if (values.frame) { 162 FSPACE[0] = Math.max(0,FSPACE[0]); 163 FSPACE[1] = Math.max(0,FSPACE[1]); 164 } 165 if (values.fspace) { 166 CSPACE[J] = FSPACE[0]; RSPACE[M] = FSPACE[1]; 167 } else { 168 CSPACE[J] = RSPACE[M] = 0; 169 } 170 CLINES[J] = RLINES[M] = MML.LINES.NONE; 171 // 172 // Save everything in the state 173 // 174 state.CSPACE = CSPACE; state.RSPACE = RSPACE; 175 state.CALIGN = CALIGN; state.RALIGN = RALIGN; 176 state.CLINES = CLINES; state.RLINES = RLINES; 177 state.CWIDTH = CWIDTH; state.RCALIGN = RCALIGN; 178 state.FSPACE = FSPACE; 179 }, 180 // 181 // Add styles to cells to handle borders, spacing, alignment, etc. 182 // 183 CHTMLadjustCells: function(values,state) { 184 var ROWS = state.rows, 185 CSPACE = state.CSPACE, CLINES = state.CLINES, 186 RSPACE = state.RSPACE, RLINES = state.RLINES, 187 CALIGN = state.CALIGN, RALIGN = state.RALIGN, 188 RCALIGN = state.RCALIGN; 189 CSPACE[state.J] *= 2; RSPACE[ROWS.length-1] *= 2; // since halved below 190 var LH = CHTML.FONTDATA.lineH * values.useHeight, 191 LD = CHTML.FONTDATA.lineD * values.useHeight; 192 var T = "0", B, R, L, border, cbox, align; 193 if (values.fspace) T = CHTML.Em(state.FSPACE[1]); 194 for (var i = 0, m = ROWS.length; i < m; i++) { 195 var row = ROWS[i], rdata = this.data[i]; 196 // 197 // Space and borders between rows 198 // 199 B = RSPACE[i]/2; border = null; L = "0"; 200 if (RLINES[i] !== MML.LINES.NONE) { 201 border = state.t+" "+RLINES[i]; 202 B -= 1/CHTML.em/2; 203 } 204 B = CHTML.Em(Math.max(0,B)); 205 // 206 // Frame space for initial cell 207 // 208 if (values.fspace) L = CHTML.Em(state.FSPACE[0]); 209 // 210 // The cells in the row 211 // 212 for (var j = 0, M = row.length; j < M; j++) { 213 var s = (rdata.type === "mtr" ? 0 : LABEL); 214 cell = row[j].style; cbox = rdata.data[j-s].CHTML; 215 // 216 // Space and borders between columns 217 // 218 R = CSPACE[j]/2; 219 if (CLINES[j] !== MML.LINES.NONE) { 220 cell.borderRight = state.t+" "+CLINES[j]; 221 R -= 1/CHTML.em/2; 222 } 223 R = CHTML.Em(Math.max(0,R)); 224 cell.padding = T+" "+R+" "+B+" "+L; 225 if (border) cell.borderBottom = border; 226 L = R; 227 // 228 // Handle vertical and horizontal alignment 229 // 230 align = (rdata.data[j-s].rowalign||this.data[i].rowalign||RALIGN[i]); 231 align = ({top:"top", bottom:"bottom", center:"middle"})[align]; 232 if (align) cell.verticalAlign = align; 233 align = (rdata.data[j-s].columnalign||RCALIGN[i][j]||CALIGN[j]); 234 if (align !== MML.ALIGN.CENTER) cell.textAlign = align; 235 // 236 // Equal heights forced by adding an element of the proper size 237 // (setting style.height seems to work very strangely) 238 // 239 if (state.HD && j === 0) { 240 CHTML.addElement(row[j].parentNode,"mjx-mtd",{style:{padding:T+" 0 "+B}}, 241 [["mjx-box",{style:{ 242 height:CHTML.Em(state.HH+state.DD), 243 "vertical-align":CHTML.Em(-state.DD) 244 }}]] 245 ); 246 } 247 // 248 // Pad cells that are too short 249 // 250 cell = row[j].firstChild.style; 251 if (cbox.h < LH) cell.marginTop = CHTML.Em(LH-cbox.h); 252 if (cbox.d < LD) cell.marginBottom = CHTML.Em(LD-cbox.d); 253 } 254 T = B; 255 } 256 CSPACE[state.J] /= 2; RSPACE[ROWS.length-1] /= 2; // back to normal 257 }, 258 // 259 // Align the table vertically according to the align attribute 260 // 261 CHTMLalignV: function (values,state,node) { 262 var n, M = state.rows.length, H = state.H, D = state.D, RSPACE = state.RSPACE; 263 // 264 // Get alignment type and row number 265 // 266 if (typeof(values.align) !== "string") values.align = String(values.align); 267 if (values.align.match(/(top|bottom|center|baseline|axis)( +(-?\d+))?/)) { 268 n = parseInt(RegExp.$3||"0"); 269 values.align = RegExp.$1 270 if (n < 0) n += state.rows.length + 1; 271 if (n > M || n <= 0) n = null; 272 } else { 273 values.align = this.defaults.align; 274 } 275 // 276 // Get table height and baseline offset 277 // 278 var T = 0, B = 0, a = CHTML.TEX.axis_height; 279 if (values.fspace) T += state.FSPACE[1]; 280 if (values.frame) {T += 2/CHTML.em; B += 1/CHTML.em} 281 var h = state.HH, d = state.DD; 282 for (var i = 0; i < M; i++) { 283 if (!state.HD) {h = H[i]; d = D[i]} 284 T += h + d + RSPACE[i]; 285 if (n) { 286 if (i === n-1) { 287 B += ({top:h+d, bottom:0, center:(h+d)/2, 288 baseline:d, axis:a+d})[values.align] + RSPACE[i]; 289 } 290 if (i >= n) B += h + d + RSPACE[i]; 291 } 292 } 293 if (!n) B = ({top:T, bottom:0, center:T/2, baseline:T/2, axis:T/2-a})[values.align]; 294 // 295 // Place the node and save the values 296 // 297 if (B) node.style.verticalAlign = CHTML.Em(-B); 298 state.T = T; state.B = B; 299 }, 300 // 301 // Determine column widths and set the styles for the columns 302 // 303 CHTMLcolumnWidths: function (values,state,node) { 304 var CWIDTH = state.CWIDTH, CSPACE = state.CSPACE, J = state.J, j; 305 var WW = 0, setWidths = false, relWidth = values.width.match(/%$/); 306 var i, m, w; 307 // 308 // Handle equal columns by adjusting the CWIDTH array 309 // 310 if (values.width !== "auto" && !relWidth) { 311 WW = Math.max(0,this.CHTMLlength2em(values.width,state.R)); 312 setWidths = true; 313 } 314 if (values.equalcolumns) { 315 if (relWidth) { 316 // 317 // Use percent of total (not perfect, but best we can do) 318 // 319 var p = CHTML.Percent(1/(J+1)); 320 for (j = 0; j <= J; j++) CWIDTH[j] = p; 321 } else { 322 // 323 // For width = auto, make all widths equal the widest, 324 // otherwise, for specific width, remove intercolumn space 325 // and divide by number of columns to get widest space. 326 // 327 w = Math.max.apply(Math,state.W); 328 if (values.width !== "auto") { 329 var S = (values.fspace ? state.FSPACE[0] + (values.frame ? 2/CHTML.em : 0) : 0); 330 for (j = 0; j <= J; j++) S += CSPACE[j]; 331 w = Math.max((WW-S)/(J+1),w); 332 } 333 w = CHTML.Em(w); 334 for (j = 0; j <= J; j++) CWIDTH[j] = w; 335 } 336 setWidths = true; 337 } 338 // 339 // Compute natural table width 340 // 341 var TW = 0; if (values.fspace) TW = state.FSPACE[0]; 342 var auto = [], fit = [], percent = [], W = []; 343 var row = state.rows[0]; 344 for (j = 0; j <= J; j++) { 345 W[j] = state.W[j]; 346 if (CWIDTH[j] === "auto") auto.push(j) 347 else if (CWIDTH[j] === "fit") fit.push(j) 348 else if (CWIDTH[j].match(/%$/)) percent.push(j) 349 else W[j] = this.CHTMLlength2em(CWIDTH[j],W[j]); 350 TW += W[j] + CSPACE[j]; 351 if (row[j]) row[j].style.width = CHTML.Em(W[j]); 352 } 353 if (values.frame) TW += 2/CHTML.em; 354 var hasFit = (fit.length > 0); 355 // 356 // Adjust widths of columns 357 // 358 if (setWidths) { 359 if (relWidth) { 360 // 361 // Attach appropriate widths to the columns 362 // 363 for (j = 0; j <= J; j++) { 364 cell = row[j].style; 365 if (CWIDTH[j] === "auto" && !hasFit) cell.width = ""; 366 else if (CWIDTH[j] === "fit") cell.width = ""; 367 else if (CWIDTH[j].match(/%$/)) cell.width = CWIDTH[j]; 368 else cell.minWidth = cell.maxWidth = cell.width; 369 } 370 } else { 371 // 372 // Compute percentage widths 373 // 374 if (WW > TW) { 375 var extra = 0; 376 for (i = 0, m = percent.length; i < m; i++) { 377 j = percent[i]; 378 w = Math.max(W[j],this.CHTMLlength2em(CWIDTH[j],WW)); 379 extra += w-W[j]; W[j] = w; 380 row[j].style.width = CHTML.Em(w); 381 } 382 TW += extra; 383 } 384 // 385 // Compute "fit" widths 386 // 387 if (!hasFit) fit = auto; 388 if (WW > TW && fit.length) { 389 var dw = (WW - TW) / fit.length; 390 for (i = 0, m = fit.length; i < m; i++) { 391 j = fit[i]; W[j] += dw; 392 row[j].style.width = CHTML.Em(W[j]); 393 } 394 TW = WW; 395 } 396 } 397 } 398 W[LABEL] = state.W[LABEL]; 399 state.W = W; 400 state.R = TW; 401 // 402 // Set variable width on DOM nodes 403 // 404 if (relWidth) { 405 this.CHTML.pwidth = values.width; this.CHTML.mwidth = CHTML.Em(TW); 406 node.style.width = node.firstChild.style.width = "100%"; 407 } 408 }, 409 // 410 // Stretch any cells that can be stretched 411 // 412 CHTMLstretchCells: function (values,state) { 413 var ROWS = state.rows, H = state.H, D = state.D, W = state.W, 414 J = state.J, M = ROWS.length-1; 415 var h = state.HH, d = state.DD; 416 for (var i = 0; i <= M; i++) { 417 var row = ROWS[i], rdata = this.data[i]; 418 if (!state.HD) {h = H[i]; d = D[i]} 419 for (var j = 0; j <= J; j++) { 420 var cell = row[j], cdata = rdata.data[j]; 421 if (!cdata) continue; 422 if (cdata.CHTML.stretch === "V") cdata.CHTMLstretchV(h,d); 423 else if (cdata.CHTML.stretch === "H") cdata.CHTMLstretchH(cell,W[j]); 424 } 425 } 426 }, 427 // 428 // Add labels to a table 429 // 430 CHTMLaddLabels: function (values,state,node,table) { 431 // 432 // Get indentation and alignment 433 // 434 var indent = this.getValues("indentalignfirst","indentshiftfirst","indentalign","indentshift"); 435 if (indent.indentalignfirst !== MML.INDENTALIGN.INDENTALIGN) indent.indentalign = indent.indentalignfirst; 436 if (indent.indentalign === MML.INDENTALIGN.AUTO) indent.indentalign = CONFIG.displayAlign; 437 if (indent.indentshiftfirst !== MML.INDENTSHIFT.INDENTSHIFT) indent.indentshift = indent.indentshiftfirst; 438 if (indent.indentshift === "auto") indent.indentshift = "0"; 439 var shift = this.CHTMLlength2em(indent.indentshift,CHTML.cwidth); 440 var labelspace = this.CHTMLlength2em(values.minlabelspacing,.8); 441 var labelW = labelspace + state.W[LABEL], labelshift = 0, tw = state.R; 442 var dIndent = this.CHTMLlength2em(CONFIG.displayIndent,CHTML.cwidth); 443 var s = (state.CALIGN[LABEL] === MML.INDENTALIGN.RIGHT ? -1 : 1); 444 if (indent.indentalign === MML.INDENTALIGN.CENTER) { 445 tw += 2 * (labelW - s*(shift + dIndent)); 446 shift += dIndent; 447 } else if (state.CALIGN[LABEL] === indent.indentalign) { 448 if (dIndent < 0) {labelshift = s*dIndent; dIndent = 0} 449 shift += s*dIndent; if (labelW > s*shift) shift = s*labelW; shift += labelshift; 450 shift *= s; tw += shift; 451 } else { 452 tw += labelW - s*shift + dIndent; 453 shift -= s*dIndent; shift *= -s; 454 } 455 // 456 // Create boxes for table and labels 457 // 458 var box = CHTML.addElement(node,"mjx-box",{ 459 style:{width:"100%","text-align":indent.indentalign} 460 }); box.appendChild(table); 461 var labels = CHTML.Element("mjx-stack"); 462 table.style.display = "inline-table"; if (!table.style.width) table.style.width = "auto"; 463 labels.style.verticalAlign = "top"; 464 table.style.verticalAlign = CHTML.Em(state.T-state.B-state.H[0]); 465 node.style.verticalAlign = ""; 466 if (shift) { 467 if (indent.indentalign === MML.INDENTALIGN.CENTER) { 468 table.style.marginLeft = CHTML.Em(shift); 469 table.style.marginRight = CHTML.Em(-shift); 470 } else { 471 var margin = "margin" + (indent.indentalign === MML.INDENTALIGN.RIGHT ? "Right" : "Left"); 472 table.style[margin] = CHTML.Em(shift); 473 } 474 } 475 // 476 // Add labels on correct side 477 // 478 if (state.CALIGN[LABEL] === "left") { 479 node.insertBefore(labels,box); 480 labels.style.marginRight = CHTML.Em(-state.W[LABEL]-labelshift); 481 if (labelshift) labels.style.marginLeft = CHTML.Em(labelshift); 482 } else { 483 node.appendChild(labels); 484 labels.style.marginLeft = CHTML.Em(-state.W[LABEL]+labelshift); 485 } 486 // 487 // Vertically align the labels with their rows 488 // 489 var LABELS = state.labels, T = 0, H = state.H, D = state.D, RSPACE = state.RSPACE; 490 if (values.fspace) T = state.FSPACE[0] + (values.frame ? 1/CHTML.em : 0); 491 var h = state.HH, d = state.DD; 492 for (var i = 0, m = LABELS.length; i < m; i++) { 493 if (!state.HD) {h = H[i]; d = D[i]} 494 if (LABELS[i] && this.data[i].data[0]) { 495 labels.appendChild(LABELS[i]); 496 var lbox = this.data[i].data[0].CHTML; 497 T += h - lbox.h; 498 if (T) LABELS[i].style.marginTop = CHTML.Em(T); 499 T = d - lbox.d; 500 } else { 501 T += h + d; 502 } 503 T += RSPACE[i]; 504 } 505 // 506 // Propagate full-width equations, and reserve room for equation plus label 507 // 508 node.style.width = this.CHTML.pwidth = "100%"; 509 node.style.minWidth = this.CHTML.mwidth = CHTML.Em(Math.max(0,tw)); 510 } 511 }); 512 513 MML.mtr.Augment({ 514 toCommonHTML: function (node,options) { 515 // 516 // Create the row node 517 // 518 node = this.CHTMLcreateNode(node); 519 this.CHTMLhandleStyle(node); 520 this.CHTMLhandleScale(node); 521 // 522 // Add a new row with no label 523 // 524 if (!options) options = {rows:[],labels:[]}; 525 var row = []; options.rows.push(row); 526 options.labels.push(null); 527 // 528 // Add the cells to the row 529 // 530 for (var i = 0, m = this.data.length; i < m; i++) 531 row.push(this.CHTMLaddChild(node,i,options)); 532 // 533 this.CHTMLhandleColor(node); 534 return node; 535 } 536 }); 537 MML.mlabeledtr.Augment({ 538 toCommonHTML: function (node,options) { 539 // 540 // Create the row node 541 // 542 node = this.CHTMLcreateNode(node); 543 this.CHTMLhandleStyle(node); 544 this.CHTMLhandleScale(node); 545 // 546 // Add a new row, and get the label 547 // 548 if (!options) options = {rows:[],labels:[]}; 549 var row = []; options.rows.push(row); 550 var label = CHTML.Element("mjx-label"); options.labels.push(label); 551 this.CHTMLaddChild(label,0,options); 552 if (this.data[0]) options.labeled = true; 553 // 554 // Add the cells to the row 555 // 556 for (var i = 1, m = this.data.length; i < m; i++) 557 row.push(this.CHTMLaddChild(node,i,options)); 558 // 559 this.CHTMLhandleColor(node); 560 return node; 561 } 562 }); 563 MML.mtd.Augment({ 564 toCommonHTML: function (node,options) { 565 node = this.CHTMLdefaultNode(node,options); 566 // 567 // Determine if this is stretchy or not 568 // 569 if (this.isEmbellished()) { 570 var mo = this.CoreMO(), BBOX = this.CHTML; 571 if (mo.CHTMLcanStretch("Vertical")) BBOX.stretch = "V"; 572 else if (mo.CHTMLcanStretch("Horizontal")) BBOX.stretch = "H"; 573 if (BBOX.stretch) { 574 var min = mo.Get("minsize",true); 575 if (min) { 576 if (BBOX.stretch === "V") { 577 var HD = BBOX.h + BBOX.d; 578 if (HD) { 579 var r = this.CHTMLlength2em(min,HD)/HD; 580 if (r > 1) {BBOX.h *= r; BBOX.d *= r} 581 } 582 } else { 583 BBOX.w = Math.max(BBOX.w,this.CHTMLlength2em(min,BBOX.w)); 584 } 585 } 586 } 587 } 588 return node; 589 } 590 }); 591 592 593 MathJax.Hub.Startup.signal.Post("CommonHTML mtable Ready"); 594 MathJax.Ajax.loadComplete(CHTML.autoloadDir+"/mtable.js"); 595 }); 596