「MathJaxをデバッグしてJavaScriptの理解を深める」の版間の差分
(→概要) |
|||
(同じ利用者による、間の46版が非表示) | |||
1行目: | 1行目: | ||
[[VScodeで簡易WebServerの元でデバッグ]]に戻る。 | [[VScodeで簡易WebServerの元でデバッグ]]に戻る。 | ||
[[MathJaxをデバッグしてJavaScriptの理解を深める|[1]]] [[MathJaxをデバッグしてJavaScriptの理解を深める ページ2|[2]]] [[MathJaxをデバッグしてJavaScriptの理解を深める ページ3|[3]]] [[MathJaxをデバッグしてJavaScriptの理解を深める ページ4|[4]]] | |||
9行目: | 11行目: | ||
MathJaxに使われている技術を理解してく記事です。途中まで読み進めるだけで充分そのエッセンスを吸収できると思いますので、<span style="color: darkred;">'''全てを解析するのではなく、途中まで読んでみるというものです。期待し過ぎないで下さい。'''</span>結果的に[[JAVA Script]]のページのリファレンスが少しだけ実用レベルのリファレンスくらいに充実するということを狙っています。そして理解するための工夫や解析によってわかったMathJaxの考え方をここで書いていきます。自分が使ったことのあるのはMathJaxの中の/es5/tex-mml-chtml.jsで、これをちょろっと覗くとまぁエグイ。こういうのを覘くっていうんだっけ?一行目で終わってるプログラム。さすが、一行の長さがエグイ。インデントしてみたら5万行にもわたるプログラムが1行になってる。改行なしのプログラムあるんだなぁ。 | |||
ちなみに解の公式のサンプルは以下のような結果を得るためのライブラリだ。 | |||
<syntaxhighlight lang='html'> | |||
<head> | |||
== | <meta charset="utf-8"> | ||
<meta http-equiv="x-ua-compatible" content="ie=edge"> | |||
<meta name="viewport" content="width=device-width"> | |||
<title>MathJax v3 with customized list of components</title> | |||
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> | |||
<script> | |||
MathJax = { | |||
loader: { | |||
load: ['input/tex-base', '[tex]/newcommand', '[tex]/action', 'output/chtml'] | |||
}, | |||
tex: { | |||
inlineMath: [ | |||
['$', '$'], | |||
['\\(', '\\)'] | |||
], | |||
packages: ['base', 'newcommand', 'action'] | |||
} | |||
}; | |||
</script> | |||
<script id="MathJax-script" async="" src="../es5/tex-mml-chtml.js"></script> | |||
<script src="file:///C:/MathJax/es5/input/tex/extensions/action.js" charset="UTF-8"></script> | |||
<style type="text/css"> | |||
.CtxtMenu_InfoClose { | |||
top: .2em; | |||
right: .2em; | |||
} | |||
.CtxtMenu_InfoContent { | |||
overflow: auto; | |||
text-align: left; | |||
font-size: 80%; | |||
padding: .4em .6em; | |||
border: 1px inset; | |||
margin: 1em 0px; | |||
max-height: 20em; | |||
max-width: 30em; | |||
background-color: #EEEEEE; | |||
white-space: normal; | |||
} | |||
.CtxtMenu_Info.CtxtMenu_MousePost { | |||
outline: none; | |||
} | |||
.CtxtMenu_Info { | |||
position: fixed; | |||
left: 50%; | |||
width: auto; | |||
text-align: center; | |||
border: 3px outset; | |||
padding: 1em 2em; | |||
background-color: #DDDDDD; | |||
color: black; | |||
cursor: default; | |||
font-family: message-box; | |||
font-size: 120%; | |||
font-style: normal; | |||
text-indent: 0; | |||
text-transform: none; | |||
line-height: normal; | |||
letter-spacing: normal; | |||
word-spacing: normal; | |||
word-wrap: normal; | |||
white-space: nowrap; | |||
< | float: none; | ||
z-index: 201; | |||
border-radius: 15px; | |||
/* Opera 10.5 and IE9 */ | |||
-webkit-border-radius: 15px; | |||
/* Safari and Chrome */ | |||
}; | -moz-border-radius: 15px; | ||
/* Firefox */ | |||
-khtml-border-radius: 15px; | |||
/* Konqueror */ | |||
box-shadow: 0px 10px 20px #808080; | |||
/* Opera 10.5 and IE9 */ | |||
-webkit-box-shadow: 0px 10px 20px #808080; | |||
/* Safari 3 & Chrome */ | |||
-moz-box-shadow: 0px 10px 20px #808080; | |||
/* Forefox 3.5 */ | |||
-khtml-box-shadow: 0px 10px 20px #808080; | |||
/* Konqueror */ | |||
filter: progid: DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color="gray", Positive="true"); | |||
/* IE */ | |||
} | |||
</style> | |||
<style type="text/css"> | |||
.CtxtMenu_MenuClose { | |||
position: absolute; | |||
cursor: pointer; | |||
display: inline-block; | |||
border: 2px solid #AAA; | |||
border-radius: 18px; | |||
-webkit-border-radius: 18px; | |||
/* Safari and Chrome */ | |||
-moz-border-radius: 18px; | |||
/* Firefox */ | |||
-khtml-border-radius: 18px; | |||
/* Konqueror */ | |||
font-family: "Courier New", Courier; | |||
font-size: 24px; | |||
color: #F0F0F0 | |||
} | |||
.CtxtMenu_MenuClose span { | |||
display: block; | |||
background-color: #AAA; | |||
border: 1.5px solid; | |||
border-radius: 18px; | |||
-webkit-border-radius: 18px; | |||
/* Safari and Chrome */ | |||
-moz-border-radius: 18px; | |||
/* Firefox */ | |||
-khtml-border-radius: 18px; | |||
/* Konqueror */ | |||
line-height: 0; | |||
padding: 8px 0 6px/* may need to be browser-specific */ | |||
} | |||
.CtxtMenu_MenuClose:hover { | |||
color: white!important; | |||
border: 2px solid #CCC!important | |||
} | |||
.CtxtMenu_MenuClose:hover span { | |||
background-color: #CCC!important | |||
} | |||
.CtxtMenu_MenuClose:hover:focus { | |||
outline: none | |||
} | |||
</style> | |||
<style type="text/css"> | |||
.CtxtMenu_Menu { | |||
position: absolute; | |||
background-color: white; | |||
color: black; | |||
width: auto; | |||
padding: 5px 0px; | |||
border: 1px solid #CCCCCC; | |||
margin: 0; | |||
cursor: default; | |||
font: menu; | |||
text-align: left; | |||
text-indent: 0; | |||
text-transform: none; | |||
line-height: normal; | |||
letter-spacing: normal; | |||
word-spacing: normal; | |||
word-wrap: normal; | |||
white-space: nowrap; | |||
float: none; | |||
z-index: 201; | |||
border-radius: 5px; | |||
/* Opera 10.5 and IE9 */ | |||
-webkit-border-radius: 5px; | |||
/* Safari and Chrome */ | |||
-moz-border-radius: 5px; | |||
/* Firefox */ | |||
-khtml-border-radius: 5px; | |||
/* Konqueror */ | |||
box-shadow: 0px 10px 20px #808080; | |||
/* Opera 10.5 and IE9 */ | |||
-webkit-box-shadow: 0px 10px 20px #808080; | |||
/* Safari 3 & Chrome */ | |||
-moz-box-shadow: 0px 10px 20px #808080; | |||
/* Forefox 3.5 */ | |||
-khtml-box-shadow: 0px 10px 20px #808080; | |||
/* Konqueror */ | |||
} | |||
.CtxtMenu_MenuItem { | |||
padding: 1px 2em; | |||
background: transparent; | |||
} | |||
.CtxtMenu_MenuArrow { | |||
position: absolute; | |||
right: .5em; | |||
padding-top: .25em; | |||
color: #666666; | |||
font-family: null; | |||
font-size: .75em | |||
} | |||
.CtxtMenu_MenuActive .CtxtMenu_MenuArrow { | |||
color: white | |||
} | |||
.CtxtMenu_MenuArrow.CtxtMenu_RTL { | |||
left: .5em; | |||
right: auto | |||
} | |||
.CtxtMenu_MenuCheck { | |||
position: absolute; | |||
left: .7em; | |||
font-family: null | |||
} | |||
.CtxtMenu_MenuCheck.CtxtMenu_RTL { | |||
right: .7em; | |||
left: auto | |||
} | |||
.CtxtMenu_MenuRadioCheck { | |||
position: absolute; | |||
left: .7em; | |||
} | |||
.CtxtMenu_MenuRadioCheck.CtxtMenu_RTL { | |||
right: .7em; | |||
left: auto | |||
} | |||
.CtxtMenu_MenuInputBox { | |||
padding-left: 1em; | |||
right: .5em; | |||
color: #666666; | |||
font-family: null; | |||
} | |||
.CtxtMenu_MenuInputBox.CtxtMenu_RTL { | |||
left: .1em; | |||
} | |||
.CtxtMenu_MenuComboBox { | |||
left: .1em; | |||
padding-bottom: .5em; | |||
} | |||
.CtxtMenu_MenuSlider { | |||
left: .1em; | |||
} | |||
.CtxtMenu_SliderValue { | |||
position: absolute; | |||
right: .1em; | |||
padding-top: .25em; | |||
color: #333333; | |||
font-size: .75em | |||
} | |||
.CtxtMenu_SliderBar { | |||
outline: none; | |||
background: #d3d3d3 | |||
} | |||
.CtxtMenu_MenuLabel { | |||
padding: 1px 2em 3px 1.33em; | |||
font-style: italic | |||
} | |||
.CtxtMenu_MenuRule { | |||
border-top: 1px solid #DDDDDD; | |||
margin: 4px 3px; | |||
} | |||
.CtxtMenu_MenuDisabled { | |||
color: GrayText | |||
} | |||
.CtxtMenu_MenuActive { | |||
background-color: #606872; | |||
color: white; | |||
} | |||
.CtxtMenu_MenuDisabled:focus { | |||
background-color: #E8E8E8 | |||
} | |||
.CtxtMenu_MenuLabel:focus { | |||
background-color: #E8E8E8 | |||
} | |||
.CtxtMenu_ContextMenu:focus { | |||
outline: none | |||
} | |||
.CtxtMenu_ContextMenu .CtxtMenu_MenuItem:focus { | |||
outline: none | |||
} | |||
.CtxtMenu_SelectionMenu { | |||
position: relative; | |||
float: left; | |||
border-bottom: none; | |||
-webkit-box-shadow: none; | |||
-webkit-border-radius: 0px; | |||
} | |||
.CtxtMenu_SelectionItem { | |||
padding-right: 1em; | |||
} | |||
.CtxtMenu_Selection { | |||
right: 40%; | |||
width: 50%; | |||
} | |||
.CtxtMenu_SelectionBox { | |||
padding: 0em; | |||
max-height: 20em; | |||
max-width: none; | |||
background-color: #FFFFFF; | |||
} | |||
.CtxtMenu_SelectionDivider { | |||
clear: both; | |||
border-top: 2px solid #000000; | |||
} | |||
.CtxtMenu_Menu .CtxtMenu_MenuClose { | |||
top: -10px; | |||
left: -10px | |||
} | |||
</style> | |||
<style id="MJX-CHTML-styles"> | |||
mjx-container[jax="CHTML"] { | |||
line-height: 0; | |||
} | |||
mjx-container [space="1"] { | |||
margin-left: .111em; | |||
} | |||
mjx-container [space="2"] { | |||
margin-left: .167em; | |||
} | |||
mjx-container [space="3"] { | |||
margin-left: .222em; | |||
} | |||
mjx-container [space="4"] { | |||
margin-left: .278em; | |||
} | |||
mjx-container [space="5"] { | |||
margin-left: .333em; | |||
} | |||
mjx-container [rspace="1"] { | |||
margin-right: .111em; | |||
} | |||
mjx-container [rspace="2"] { | |||
margin-right: .167em; | |||
} | |||
mjx-container [rspace="3"] { | |||
margin-right: .222em; | |||
} | |||
mjx-container [rspace="4"] { | |||
margin-right: .278em; | |||
} | |||
mjx-container [rspace="5"] { | |||
margin-right: .333em; | |||
} | |||
mjx-container [size="s"] { | |||
font-size: 70.7%; | |||
} | |||
mjx-container [size="ss"] { | |||
font-size: 50%; | |||
} | |||
mjx-container [size="Tn"] { | |||
font-size: 60%; | |||
} | |||
mjx-container [size="sm"] { | |||
font-size: 85%; | |||
} | |||
mjx-container [size="lg"] { | |||
font-size: 120%; | |||
} | |||
mjx-container [size="Lg"] { | |||
font-size: 144%; | |||
} | |||
mjx-container [size="LG"] { | |||
font-size: 173%; | |||
} | |||
mjx-container [size="hg"] { | |||
font-size: 207%; | |||
} | |||
mjx-container [size="HG"] { | |||
font-size: 249%; | |||
} | |||
mjx-container [width="full"] { | |||
width: 100%; | |||
} | |||
mjx-box { | |||
display: inline-block; | |||
} | |||
mjx-block { | |||
display: block; | |||
} | |||
mjx-itable { | |||
display: inline-table; | |||
} | |||
mjx-row { | |||
display: table-row; | |||
} | |||
mjx-row > * { | |||
display: table-cell; | |||
} | |||
mjx-mtext { | |||
display: inline-block; | |||
} | |||
mjx-mstyle { | |||
display: inline-block; | |||
} | } | ||
mjx-merror { | |||
display: inline-block; | |||
color: red; | |||
background-color: yellow; | |||
} | |||
mjx-mphantom { | |||
visibility: hidden; | |||
} | |||
_::-webkit-full-page-media, | |||
_:future, | |||
:root mjx-container { | |||
will-change: opacity; | |||
} | |||
mjx-assistive-mml { | |||
position: absolute !important; | |||
top: 0px; | |||
left: 0px; | |||
clip: rect(1px, 1px, 1px, 1px); | |||
padding: 1px 0px 0px 0px !important; | |||
border: 0px !important; | |||
display: block !important; | |||
width: auto !important; | |||
overflow: hidden !important; | |||
-webkit-touch-callout: none; | |||
-webkit-user-select: none; | |||
-khtml-user-select: none; | |||
-moz-user-select: none; | |||
-ms-user-select: none; | |||
user-select: none; | |||
} | |||
mjx-assistive-mml[display="block"] { | |||
width: 100% !important; | |||
} | |||
mjx-math { | |||
display: inline-block; | |||
text-align: left; | |||
line-height: 0; | |||
text-indent: 0; | |||
font-style: normal; | |||
font-weight: normal; | |||
font-size: 100%; | |||
font-size-adjust: none; | |||
letter-spacing: normal; | |||
border-collapse: collapse; | |||
word-wrap: normal; | |||
word-spacing: normal; | |||
white-space: nowrap; | |||
direction: ltr; | |||
padding: 1px 0; | |||
} | |||
mjx-container[jax="CHTML"][display="true"] { | |||
display: block; | |||
text-align: center; | |||
margin: 1em 0; | |||
} | |||
mjx-container[jax="CHTML"][display="true"][width="full"] { | |||
display: flex; | |||
} | |||
mjx-container[jax="CHTML"][display="true"] mjx-math { | |||
padding: 0; | |||
} | |||
mjx-container[jax="CHTML"][justify="left"] { | |||
text-align: left; | |||
} | |||
mjx-container[jax="CHTML"][justify="right"] { | |||
text-align: right; | |||
} | |||
mjx-mi { | |||
display: inline-block; | |||
text-align: left; | |||
} | |||
mjx-c { | |||
display: inline-block; | |||
} | |||
mjx-utext { | |||
display: inline-block; | |||
padding: .75em 0 .2em 0; | |||
} | |||
mjx-mo { | |||
display: inline-block; | |||
text-align: left; | |||
} | |||
mjx-stretchy-h { | |||
display: inline-table; | |||
width: 100%; | |||
} | |||
mjx-stretchy-h > * { | |||
display: table-cell; | |||
width: 0; | |||
} | |||
mjx-stretchy-h > * > mjx-c { | |||
display: inline-block; | |||
transform: scalex(1.0000001); | |||
} | |||
mjx-stretchy-h > * > mjx-c::before { | |||
display: inline-block; | |||
width: initial; | |||
} | |||
mjx-stretchy-h > mjx-ext { | |||
/* IE */ | |||
overflow: hidden; | |||
/* others */ | |||
overflow: clip visible; | |||
width: 100%; | |||
} | |||
mjx-stretchy-h > mjx-ext > mjx-c::before { | |||
transform: scalex(500); | |||
} | |||
mjx-stretchy-h > mjx-ext > mjx-c { | |||
width: 0; | |||
} | |||
mjx-stretchy-h > mjx-beg > mjx-c { | |||
margin-right: -.1em; | |||
} | |||
mjx-stretchy-h > mjx-end > mjx-c { | |||
margin-left: -.1em; | |||
} | |||
mjx-stretchy-v { | |||
display: inline-block; | |||
} | |||
mjx-stretchy-v > * { | |||
display: block; | |||
} | |||
mjx-stretchy-v > mjx-beg { | |||
height: 0; | |||
} | |||
mjx-stretchy-v > mjx-end > mjx-c { | |||
display: block; | |||
} | |||
mjx-stretchy-v > * > mjx-c { | |||
transform: scaley(1.0000001); | |||
transform-origin: left center; | |||
overflow: hidden; | |||
} | |||
mjx-stretchy-v > mjx-ext { | |||
display: block; | |||
height: 100%; | |||
box-sizing: border-box; | |||
border: 0px solid transparent; | |||
/* IE */ | |||
overflow: hidden; | |||
/* others */ | |||
overflow: visible clip; | |||
} | |||
mjx-stretchy-v > mjx-ext > mjx-c::before { | |||
width: initial; | |||
box-sizing: border-box; | |||
} | |||
mjx-stretchy-v > mjx-ext > mjx-c { | |||
transform: scaleY(500) translateY(.075em); | |||
overflow: visible; | |||
} | |||
mjx-mark { | |||
display: inline-block; | |||
height: 0px; | |||
} | |||
mjx-mn { | |||
display: inline-block; | |||
text-align: left; | |||
} | |||
mjx-msup { | |||
display: inline-block; | |||
text-align: left; | |||
} | |||
mjx-TeXAtom { | |||
display: inline-block; | |||
text-align: left; | |||
} | |||
mjx-mfrac { | |||
display: inline-block; | |||
text-align: left; | |||
} | |||
mjx-frac { | |||
display: inline-block; | |||
vertical-align: 0.17em; | |||
padding: 0 .22em; | |||
} | |||
mjx-frac[type="d"] { | |||
vertical-align: .04em; | |||
} | |||
mjx-frac[delims] { | |||
padding: 0 .1em; | |||
} | |||
mjx-frac[atop] { | |||
padding: 0 .12em; | |||
} | |||
mjx-frac[atop][delims] { | |||
padding: 0; | |||
} | |||
mjx-dtable { | |||
display: inline-table; | |||
width: 100%; | |||
} | |||
mjx-dtable > * { | |||
font-size: 2000%; | |||
} | |||
mjx-dbox { | |||
display: block; | |||
font-size: 5%; | |||
} | |||
mjx-num { | |||
display: block; | |||
text-align: center; | |||
} | |||
mjx-den { | |||
display: block; | |||
text-align: center; | |||
} | |||
mjx-mfrac[bevelled] > mjx-num { | |||
display: inline-block; | |||
} | |||
mjx-mfrac[bevelled] > mjx-den { | |||
display: inline-block; | |||
} | |||
mjx-den[align="right"], | |||
mjx-num[align="right"] { | |||
text-align: right; | |||
} | |||
mjx-den[align="left"], | |||
mjx-num[align="left"] { | |||
text-align: left; | |||
} | |||
mjx-nstrut { | |||
display: inline-block; | |||
height: .054em; | |||
width: 0; | |||
vertical-align: -.054em; | |||
} | |||
mjx-nstrut[type="d"] { | |||
height: .217em; | |||
vertical-align: -.217em; | |||
} | |||
mjx-dstrut { | |||
display: inline-block; | |||
height: .505em; | |||
width: 0; | |||
} | |||
mjx-dstrut[type="d"] { | |||
height: .726em; | |||
} | |||
mjx-line { | |||
display: block; | |||
box-sizing: border-box; | |||
min-height: 1px; | |||
height: .06em; | |||
border-top: .06em solid; | |||
margin: .06em -.1em; | |||
overflow: hidden; | |||
} | |||
mjx-line[type="d"] { | |||
margin: .18em -.1em; | |||
} | |||
mjx-mrow { | |||
display: inline-block; | |||
text-align: left; | |||
} | |||
mjx-msqrt { | |||
display: inline-block; | |||
text-align: left; | |||
} | |||
mjx-root { | |||
display: inline-block; | |||
white-space: nowrap; | |||
} | |||
mjx-surd { | |||
display: inline-block; | |||
vertical-align: top; | |||
} | |||
mjx-sqrt { | |||
display: inline-block; | |||
padding-top: .07em; | |||
} | |||
mjx-sqrt > mjx-box { | |||
border-top: .07em solid; | |||
} | |||
mjx-sqrt.mjx-tall > mjx-box { | |||
padding-left: .3em; | |||
margin-left: -.3em; | |||
} | |||
mjx-maction { | |||
display: inline-block; | |||
text-align: left; | |||
position: relative; | |||
} | |||
mjx-maction > mjx-tool { | |||
display: none; | |||
position: absolute; | |||
bottom: 0; | |||
right: 0; | |||
width: 0; | |||
height: 0; | |||
z-index: 500; | |||
} | |||
mjx-tool > mjx-tip { | |||
display: inline-block; | |||
padding: .2em; | |||
border: 1px solid #888; | |||
font-size: 70%; | |||
background-color: #F8F8F8; | |||
color: black; | |||
box-shadow: 2px 2px 5px #AAAAAA; | |||
} | |||
mjx-maction[toggle] { | |||
cursor: pointer; | |||
} | |||
mjx-status { | |||
display: block; | |||
position: fixed; | |||
left: 1em; | |||
bottom: 1em; | |||
min-width: 25%; | |||
padding: .2em .4em; | |||
border: 1px solid #888; | |||
font-size: 90%; | |||
background-color: #F8F8F8; | |||
color: black; | |||
} | |||
mjx-c::before { | |||
display: block; | |||
width: 0; | |||
} | |||
.MJX-TEX { | |||
font-family: MJXZERO, MJXTEX; | |||
} | |||
.TEX-B { | |||
font-family: MJXZERO, MJXTEX-B; | |||
} | |||
.TEX-I { | |||
font-family: MJXZERO, MJXTEX-I; | |||
} | |||
.TEX-MI { | |||
font-family: MJXZERO, MJXTEX-MI; | |||
} | |||
.TEX-BI { | |||
font-family: MJXZERO, MJXTEX-BI; | |||
} | |||
.TEX-S1 { | |||
font-family: MJXZERO, MJXTEX-S1; | |||
} | |||
.TEX-S2 { | |||
font-family: MJXZERO, MJXTEX-S2; | |||
} | |||
.TEX-S3 { | |||
font-family: MJXZERO, MJXTEX-S3; | |||
} | |||
.TEX-S4 { | |||
font-family: MJXZERO, MJXTEX-S4; | |||
} | |||
.TEX-A { | |||
font-family: MJXZERO, MJXTEX-A; | |||
} | |||
.TEX-C { | |||
font-family: MJXZERO, MJXTEX-C; | |||
} | |||
.TEX-CB { | |||
font-family: MJXZERO, MJXTEX-CB; | |||
} | |||
.TEX-FR { | |||
font-family: MJXZERO, MJXTEX-FR; | |||
} | |||
.TEX-FRB { | |||
font-family: MJXZERO, MJXTEX-FRB; | |||
} | |||
.TEX-SS { | |||
font-family: MJXZERO, MJXTEX-SS; | |||
} | |||
.TEX-SSB { | |||
font-family: MJXZERO, MJXTEX-SSB; | |||
} | |||
.TEX-SSI { | |||
font-family: MJXZERO, MJXTEX-SSI; | |||
} | |||
.TEX-SC { | |||
font-family: MJXZERO, MJXTEX-SC; | |||
} | |||
.TEX-T { | |||
font-family: MJXZERO, MJXTEX-T; | |||
} | |||
.TEX-V { | |||
font-family: MJXZERO, MJXTEX-V; | |||
} | |||
.TEX-VB { | |||
font-family: MJXZERO, MJXTEX-VB; | |||
} | |||
mjx-stretchy-v mjx-c, | |||
mjx-stretchy-h mjx-c { | |||
font-family: MJXZERO, MJXTEX-S1, MJXTEX-S4, MJXTEX, MJXTEX-A ! important; | |||
} | |||
@font-face | |||
/* 0 */ | |||
{ | |||
font-family: MJXZERO; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Zero.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 1 */ | |||
{ | |||
font-family: MJXTEX; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Main-Regular.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 2 */ | |||
{ | |||
font-family: MJXTEX-B; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Main-Bold.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 3 */ | |||
{ | |||
font-family: MJXTEX-I; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Math-Italic.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 4 */ | |||
{ | |||
font-family: MJXTEX-MI; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Main-Italic.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 5 */ | |||
{ | |||
font-family: MJXTEX-BI; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Math-BoldItalic.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 6 */ | |||
{ | |||
font-family: MJXTEX-S1; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Size1-Regular.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 7 */ | |||
{ | |||
font-family: MJXTEX-S2; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Size2-Regular.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 8 */ | |||
{ | |||
font-family: MJXTEX-S3; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Size3-Regular.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 9 */ | |||
{ | |||
font-family: MJXTEX-S4; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Size4-Regular.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 10 */ | |||
{ | |||
font-family: MJXTEX-A; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_AMS-Regular.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 11 */ | |||
{ | |||
font-family: MJXTEX-C; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Regular.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 12 */ | |||
{ | |||
font-family: MJXTEX-CB; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Bold.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 13 */ | |||
{ | |||
font-family: MJXTEX-FR; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Fraktur-Regular.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 14 */ | |||
{ | |||
font-family: MJXTEX-FRB; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Fraktur-Bold.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 15 */ | |||
{ | |||
font-family: MJXTEX-SS; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_SansSerif-Regular.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 16 */ | |||
{ | |||
font-family: MJXTEX-SSB; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_SansSerif-Bold.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 17 */ | |||
{ | |||
font-family: MJXTEX-SSI; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_SansSerif-Italic.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 18 */ | |||
{ | |||
font-family: MJXTEX-SC; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Script-Regular.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 19 */ | |||
{ | |||
font-family: MJXTEX-T; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Typewriter-Regular.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 20 */ | |||
{ | |||
font-family: MJXTEX-V; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Vector-Regular.woff") format("woff"); | |||
} | |||
@font-face | |||
/* 21 */ | |||
{ | |||
font-family: MJXTEX-VB; | |||
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Vector-Bold.woff") format("woff"); | |||
} | |||
mjx-c.mjx-c1D44E.TEX-I::before { | |||
padding: 0.441em 0.529em 0.01em 0; | |||
content: "a"; | |||
} | |||
mjx-c.mjx-c2260::before { | |||
padding: 0.716em 0.778em 0.215em 0; | |||
content: "\2260"; | |||
} | |||
mjx-c.mjx-c30::before { | |||
padding: 0.666em 0.5em 0.022em 0; | |||
content: "0"; | |||
} | |||
mjx-c.mjx-c1D465.TEX-I::before { | |||
padding: 0.442em 0.572em 0.011em 0; | |||
content: "x"; | |||
} | |||
mjx-c.mjx-c32::before { | |||
padding: 0.666em 0.5em 0 0; | |||
content: "2"; | |||
} | |||
mjx-c.mjx-c2B::before { | |||
padding: 0.583em 0.778em 0.082em 0; | |||
content: "+"; | |||
} | |||
mjx-c.mjx-c1D44F.TEX-I::before { | |||
padding: 0.694em 0.429em 0.011em 0; | |||
content: "b"; | |||
} | |||
mjx-c.mjx-c1D450.TEX-I::before { | |||
padding: 0.442em 0.433em 0.011em 0; | |||
content: "c"; | |||
} | |||
mjx-c.mjx-c3D::before { | |||
padding: 0.583em 0.778em 0.082em 0; | |||
content: "="; | |||
} | |||
mjx-c.mjx-c2212::before { | |||
padding: 0.583em 0.778em 0.082em 0; | |||
content: "\2212"; | |||
} | |||
mjx-c.mjx-cB1::before { | |||
padding: 0.666em 0.778em 0 0; | |||
content: "\B1"; | |||
} | |||
mjx-c.mjx-c221A::before { | |||
padding: 0.8em 0.853em 0.2em 0; | |||
content: "\221A"; | |||
} | |||
mjx-c.mjx-c34::before { | |||
padding: 0.677em 0.5em 0 0; | |||
content: "4"; | |||
} | |||
mjx-c.mjx-c2E::before { | |||
padding: 0.12em 0.278em 0 0; | |||
content: "."; | |||
} | |||
</style> | |||
</head> | |||
<body> | |||
<mjx-container class="MathJax CtxtMenu_Attached_0" jax="CHTML" display="true" tabindex="0" ctxtmenu_counter="2" style="font-size: 124.9%; position: relative;"> | |||
<mjx-math display="true" class="MJX-TEX" aria-hidden="true" style="margin-left: 0px; margin-right: 0px;"> | |||
<mjx-mi class="mjx-i"> | |||
<mjx-c class="mjx-c1D465 TEX-I"></mjx-c> | |||
</mjx-mi> | |||
<mjx-mo class="mjx-n" space="4"> | |||
<mjx-c class="mjx-c3D"></mjx-c> | |||
</mjx-mo> | |||
<mjx-texatom space="4" texclass="ORD"> | |||
<mjx-mfrac> | |||
<mjx-frac type="d"> | |||
<mjx-num> | |||
<mjx-nstrut type="d"></mjx-nstrut> | |||
<mjx-mrow> | |||
<mjx-mo class="mjx-n"> | |||
<mjx-c class="mjx-c2212"></mjx-c> | |||
</mjx-mo> | |||
<mjx-mi class="mjx-i"> | |||
<mjx-c class="mjx-c1D44F TEX-I"></mjx-c> | |||
</mjx-mi> | |||
<mjx-mo class="mjx-n" space="3"> | |||
<mjx-c class="mjx-cB1"></mjx-c> | |||
</mjx-mo> | |||
<mjx-msqrt space="3"> | |||
<mjx-sqrt> | |||
<mjx-surd> | |||
<mjx-mo class="mjx-n"> | |||
<mjx-c class="mjx-c221A"></mjx-c> | |||
</mjx-mo> | |||
</mjx-surd> | |||
<mjx-box style="padding-top: 0.087em;"> | |||
<mjx-maction title="descriminant"> | |||
<mjx-mrow> | |||
<mjx-msup> | |||
<mjx-mi class="mjx-i"> | |||
<mjx-c class="mjx-c1D44F TEX-I"></mjx-c> | |||
</mjx-mi> | |||
<mjx-script style="vertical-align: 0.289em;"> | |||
<mjx-mn class="mjx-n" size="s"> | |||
<mjx-c class="mjx-c32"></mjx-c> | |||
</mjx-mn> | |||
</mjx-script> | |||
</mjx-msup> | |||
<mjx-mo class="mjx-n" space="3"> | |||
<mjx-c class="mjx-c2212"></mjx-c> | |||
</mjx-mo> | |||
<mjx-mn class="mjx-n" space="3"> | |||
<mjx-c class="mjx-c34"></mjx-c> | |||
</mjx-mn> | |||
<mjx-mi class="mjx-i"> | |||
<mjx-c class="mjx-c1D44E TEX-I"></mjx-c> | |||
</mjx-mi> | |||
<mjx-mi class="mjx-i"> | |||
<mjx-c class="mjx-c1D450 TEX-I"></mjx-c> | |||
</mjx-mi> | |||
</mjx-mrow> | |||
</mjx-maction> | |||
</mjx-box> | |||
</mjx-sqrt> | |||
</mjx-msqrt> | |||
</mjx-mrow> | |||
</mjx-num> | |||
<mjx-dbox> | |||
<mjx-dtable> | |||
<mjx-line type="d"></mjx-line> | |||
<mjx-row> | |||
<mjx-den> | |||
<mjx-dstrut type="d"></mjx-dstrut> | |||
<mjx-mrow> | |||
<mjx-mn class="mjx-n"> | |||
<mjx-c class="mjx-c32"></mjx-c> | |||
</mjx-mn> | |||
<mjx-mi class="mjx-i"> | |||
<mjx-c class="mjx-c1D44E TEX-I"></mjx-c> | |||
</mjx-mi> | |||
</mjx-mrow> | |||
</mjx-den> | |||
</mjx-row> | |||
</mjx-dtable> | |||
</mjx-dbox> | |||
</mjx-frac> | |||
</mjx-mfrac> | |||
</mjx-texatom> | |||
<mjx-mo class="mjx-n"> | |||
<mjx-c class="mjx-c2E"></mjx-c> | |||
</mjx-mo> | |||
</mjx-math> | |||
<mjx-assistive-mml unselectable="on" display="block"> | |||
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> | |||
<mi>x</mi> | |||
<mo>=</mo> | |||
<mrow data-mjx-texclass="ORD"> | |||
<mfrac> | |||
<mrow> | |||
<mo>−</mo> | |||
<mi>b</mi> | |||
<mo>±</mo> | |||
<msqrt> | |||
<maction actiontype="tooltip"> | |||
<mrow> | |||
<msup> | |||
<mi>b</mi> | |||
<mn>2</mn> | |||
</msup> | |||
<mo>−</mo> | |||
<mn>4</mn> | |||
<mi>a</mi> | |||
<mi>c</mi> | |||
</mrow> | |||
<mtext>descriminant</mtext> | |||
</maction> | |||
</msqrt> | |||
</mrow> | |||
<mrow> | |||
<mn>2</mn> | |||
<mi>a</mi> | |||
</mrow> | |||
</mfrac> | |||
</mrow> | |||
<mo>.</mo> | |||
</math> | |||
</mjx-assistive-mml> | |||
</mjx-container> | |||
</body> | |||
</syntaxhighlight> | |||
まずは、インデント処理を自動でやってくれるサービスと出会うことから始めました。 | |||
== '''いろいろなプログラムを自動整形するサービス''' == | |||
MathJaxを理解する作業をはじめて、いきなりありがたいサービスにまた出会う。このサービスのプログラムもすごいね。完璧すぎる自動整形インデント処理をしてくれます。そのJavaScriptの自動整形サイトが以下です。 | |||
*Online Javascript Beautifier - BeautifyConverter.com | |||
:[https://www.beautifyconverter.com/javascript-beautifier.php https://www.beautifyconverter.com/javascript-beautifier.php] | |||
他にもBeautifier Minifier/CSV/Excel/TSV/HTML/JSON/SQL/XML/YAML/Validators/CSS/Gen/Unit/Escape/IMG/PDF/IP/Color/Othersという整形処理ができる。自分で作ったプログラムが画期的である場合にはこのような自動整形処理を他人に任せるのは知的財産の流出の危険があるので、気を付けてください。信頼できるサイトもあるかもしれませんが、自分は知りません。サービス自体はありがたい。Microsoftがこういう機能をVisualStudioCodeにつけていたら楽だったのにな。あるっちゃあるんすよ。Shift+Alt+Fらしい。あまり自動整形されないっす。 | |||
とはいいつつも自動整形が必要なのはここまでヒドイと思ったプログラムだけですけどね。自分でプログラム作成して整形したものが最高に美しい。余計なことをするのがMicrosoftのエディタって感じですけど、Microsoftの考え方と共鳴しながらのコーディングをして、美しさを求めるのが自分流。MathJaxを自動整形して見えてくるものはある。最初の方に関数が連想配列でつめこまれて1000から3000くらいの関数が配列化されている。しかも番号だけで管理している。手ごわい。いみわからん。まったくいみわからん。変数名も1文字が多い。意味わからん。そんなことできるの?ってぐらいスゴイ。なんかそういう風にプログラムを意味わからんくする自動ツールがあるのかもしれん。でも自動整形したら少しましになった。あー、ありましたねminifyとかってサービスこれのことかな。意味のあるプログラム変数名を圧縮してしまう技。こういうのを使ってるのかもしれない。でもソースで配布してるのおかしくね。MathJaxの中の人。ちがうのか。謎のままおいておこう。 | |||
== '''デバッグ環境を整える''' == | |||
基本的には[[VScodeで簡易WebServerの元でデバッグ]]で記述した方法によってVSCodeでデバッグします。ソースのダウンロードにはGitコマンドっていうのを使いたくて、Git for Windowsみたいなのをインストールしました。Gitのインストーラーがややこしい。Ver2.38.1ですが、CommandPromptでGitコマンドが使えりゃいいかなと思ったりするだけなんですけど、ややこしい。基本デフォルト設定でインストールするだけかなと思ったんですけどところどころ触ってやらないとCommandPromptで使えるような状態にはならないらしい。インストーラは[https://gitforwindows.org/ https://gitforwindows.org/]からデカデカとあるDownloadから入手。手を加えたところを太字にするとして、おおまかな流れは | |||
実行→アプリがデバイスに変更[はい]→ライセンス確認[I Agree]→インストール先[Next]→フォルダ作成確認[はい]→ | |||
インストールオプション[Next](右クリックメニューにGitShell起動とGitBash起動を追加/大きいファイルサポート/*.gitファイルをテキストエディタで編集/*.shファイルをGitBashで起動)→スタートメニューのグループ名(GITのまま)[Next]→コミットメッセージで使うエディタは何'''[Use Vim(the ubiquitous text editor) as Git's default editor]'''-[Next]→Git initで作られるブランチ名(master (Let Git Decide:Gitに決定させよう))[Next]→パスの設定'''[Git from the command line and also from 3rd-party software(path追加Gitインストール先\Git\cmd)]'''-[Next]→OpenSSHのインストール[Use bundled OpenSSH]-[Next]→HTTPSリモートリポジトリ接続[Use the OpenSSL library]-[Next]→改行コード自動変換[Checkout Windows-style,commit Unix-style line endings(コミット処理でなんかうまくいかないときはこの設定が邪魔していることも覚えておかないといけませんよ。あまり使わない機能なので大丈夫だと思いますけど)]-[Next]→Git Bashターミナルを選択[Use MinTTY]-[Next]→Git pullの設定[Default(git pull --ff)]-[Next]→Credentioal設定[Git CredentialManager]-[Next]→オプション[Enable file system caching のみ ON]-[Next]→試験運用オプション[check無し]-[Install] | |||
あらゆるプロジェクトにおいて、GitHubでソースコードを管理する波は来ています。確実に。Gitコマンドつかえるようになったほうが良いと思います。GitHubの一人勝ちだな。一般向けに最初に納得いくものを作った人たち偉い。会社には会社の中のコード管理があると思います。Visual Source Safeなつかしい。そんなのつかっているひといるのかな。ソース管理とかしたことないからわからないことばかりだけど、必要だよね。 | |||
例えばC:¥JavaScriptフォルダを作って、そこにソースをダウンロードする場合。 | |||
cd C:¥JavaScript | |||
git clone g<span>i</span>t://github.com/mathjax/MathJax.git MathJax | |||
これだけでC:¥JavaScript¥MathJaxが出来て、その中にes5フォルダが出来上がります。es5とはEcmaScriptというJavaScriptのもう一つの規格名がありまして、これにしたがっているのがes5です。何がどう違うかは自分は完全には理解していません。これに対応している関数や配列なんかには __esModule= true という値が取得できるようになっていたりします。高度なJavaScriptではこの値を制御するみたいな記事もあります。自分はまだ理解していません。 | |||
いろいろな種類の動作を確認するサンプルもダウンロードしましょう。MathJaxの多くの機能を網羅するようなSampleってのはありがたいものです。以下のアドレスから取得できます。 | |||
*[https://github.com/mathjax/MathJax-examples https://github.com/mathjax/MathJax-examples] | |||
同じフォルダ(例C:\JavaScript\MathJax)にDownloadしましょう。結果的にC:\JavaScript\MathJax\MathJax-Example\MathJax-base\index.htmlのようなものにアクセスできるようになります。このindex.htmlには2次方程式の解の公式がサンプル表示されるようになっています。Mathjaxのプログラムの参照部分が ../MathJax.js になっているので、 ../../es5/tex-mml-chtml.js のように書き換える必要があります。全部のファイルで書き換えないとだめなのでちょっと辛いですけど、やってみましょう。ファイルによっては違うプログラムを参照した方がいいようなものもあります。これで関連記事のようなVSCodeを設定をするとデバッグができるようになります。 | |||
== '''軽く追いかけてみる''' == | |||
=== '''序盤その1''' === | |||
自動整形で変換したtex-mml-chtml.jsの1行目の (function(){ にブレークポイントを設定して、プライマリサイドバーの上から4つめ実行とデバッグを選択して、launch.jsonを作ったら、Open index.html の横にある 蛍光色黄緑 ▷ のボタンを押します。ブラウザが起動して、VisualStudioCodeのtex-mml-chtml.jsの1行目で止まります。 | |||
最初の行に"use strict";とあるので、このプログラムでは、強制的に構文チェックをするモードになり、変数定義を正式に実施していないとエラーになるモードになります。 | |||
次に __webpack_modules__ 代入処理で配列が定義されます。 {351 : … とあるので、351が最初に定義される関数みたいですね。何に使うものなのか、この番号からはあまり想像つきません。ものすごい数の配列になってそう。__webpack_modules__はいわば、関数群ですね。 | |||
次に __webpack_module_cache__ = {}; という上記関数群のためのcacheと思われる変数への初期化がされます。プログラムが進むとここにいろいろ設定されていくのでしょう。よく使うやつとかがこんなかにはいるのかな。__webpack_modules__はものスゴイ数の関数がありますので。 | |||
次に function __webpack_require__(t){ … } があるので、tという変数の引数を受け取る__webpack_require__関数が定義されています。短いです。 | |||
<syntaxhighlight lang="javascript" line start="50658"> | |||
function __webpack_require__(t) { | |||
var e = __webpack_module_cache__[t]; | |||
if(void 0 !== e) return e.exports; | |||
var r = __webpack_module_cache__[t] = { | |||
exports: {} | |||
}; | |||
return __webpack_modules__[t].call(r.exports, r, r.exports, __webpack_require__), r.exports | |||
} | |||
</syntaxhighlight> | |||
ペロッと貼っておきました。cacheの中に設定されている連想配列キー変数 t の配列値を e に取得して何もなければ t の配列値にexports : {} という連想配列を代入して、その値を更に r で覚えさせておくみたいだね。そして、最初に登場にした巨大な関数群を格納している配列 t を実行しています。 返却する値として .call は連想配列値を実行ですね。連想配列にプログラムを格納しておくという技なんだな。なるほど。その引数は、たった今、{exports:{}}とした r の exports キーの値 {} と r 全体 と また同じ、r の exports キーの値 {} と この関数全体の値 __webpack_require__ も引数にしていて4つが引数になっています。この関数群の中のひとつの実行結果が返り値の一つ目、そしてもうひとつ何回も登場するr の exports キーの値 {} を返却するみたい。 | |||
次に__webpack_require__に.gというメンバ変数をつくって、これに何やら設定する関数が実行されます。 | |||
<syntaxhighlight lang="javascript" line start="50666"> | |||
__webpack_require__.g = function() { | |||
if("object" == typeof globalThis) return globalThis; | |||
try { | |||
return this || new Function("return this")() | |||
} catch(t) { | |||
if("object" == typeof window) return window | |||
} | |||
}(); | |||
</syntaxhighlight> | |||
ここは単純だな。[[JAVA Script globalThis|globalThis]]という値を __webpack_require__.g に代入する処理なんだけど、ちゃんとobjectとして存在しているかを確認して代入している慎重さがある。globalThisというオブジェクトが無い場合は例外処理付の次の処理を実施します。tryはエラーが発生する可能性がある処理で、エラーが発生したらcatchの処理をするという感じです。返却される可能性のある値は、this || new Function("return this")() エラーになった場合は、window ですね。とにかく取得できる環境変数は取るみたいな処理ですね。catch(t)のtはエラー情報格納変数です。eを使う人も多い印象だけど、tでもいいんだね。 | |||
勉強になるのは this || [[JAVA Script new Function|new Function]]("return this")() っていう部分が無駄に感じるけど、Debugしてみると単純なthisはundefinedで、new Function("return this")()だとwindowオブジェクトがかえってきたりして、意味が違うんだなって思ったことです。そして、この場合の || の使い方がむずい。なんじゃコレ。論理和演算だからどっちかがtrueになったらtrueが返却され、両方がfalseならfalseがかえるのだろう。それも動かないときはwindowオブジェクトで扱う。 | |||
まだわからないのは | |||
*new Function("return this")()の後ろのカッコの有り無しの違い | |||
*関数構文の中のthisとfunction(){}の中のthisの違い。 | |||
また今度だな。 | |||
=== '''序盤その2''' === | |||
次にvar __webpack_exports__ = {}; で __webpack_exports__ の連想配列変数を初期化。 | |||
次はちょっと特殊 !function(){}という関数の実行処理です。戻り値のBool値が反転しそうだ。論理否定付きの関数。こんなこともできるんだな。なるほどなるほど。function xxx = {} や var xxx = { zzz : function(x,x,x) = {} }なら関数定義だけfunction(){ }なら実行する内容になるんだね。定義だけか関数だよといいながらも即実行。 | |||
次の部分からは __webpack_require__(t 【←数値】 )で5つの値 t, e, r, n, o を定義。なんの処理の関数を結び付けるのやら、みてもわからんだろうな。9515, 3282, 235, 265, 2388 暗号だな。さっきしらべたとおり __webpack_require__(t) を呼ぶと、__webpack_modules__[t].call(xx,xx,xx,xx)が実行される。__webpack_modules_cache__[t]には{ exports:{ } }が作成されている状態です。 | |||
他にも、undefinedで変数が沢山認識される。 | |||
_, _e, _n, _r, _t, _$, $r, $t, a, A, ae, Ae, an, ar, Ar, at, At, b, B, Be, bn, br, Br, bt, Bt, c, C, ce, Ce, cn, cr, Cr, ct, Ct, d, D, de, De, dn, dr, Dr, dt, Dt, e, E, ee, Ee, en, er, Er, et, Et, f, F, fe, Fe, fn, fr, Fr, ft, Ft, g, G, ge, Ge, gn, gr, Gr, gt, Gt, h, H, he, He, hn, hr, Hr, ht, Ht, i, I, ie, Ie, ir, Ir, it, It, j, J, je, Je, jr, Jr, jt, Jt, k, K, ke, Ke, kr, Kr, kt, Kt, l, L, le, Le, ln, lr, Lr, lt, Lt, m, M, me, Me, mn, mr, Mr, mt, Mt, n, N, ne, Ne, nn, nr, Nr, nt, Nt, o, O, oe, Oe, on, or, Or, ot, Ot, p, P, pe, Pe, pn, pr, Pr, pt, Pt, q, Q, qe, Qe, qr, Qr, qt, Qt, r, R, re, Re, rn, rr, Rr, rt, Rt, s, S, se, Se, sn, Sn, sr, Sr, st, St, t, T, te, Te, this, tn tr, Tr, tt, Tt, u, U, ue, Ue, un, ur, Ur, ut, Ut, v, V, ve, Ve, vn, vr, Vr, vt Vt, w, W, we, We, wr, Wr, wt, Wt, x, X, xe, Xe, xr, Xr, xt, Xt, y, Y, ye, Ye, yn, yr, Yr, yt, Yt, z, Z, ze, Ze, zr, Zr, zt, Zt | |||
上記ぐらいが定義される。アルファベット全部の小文字(26)、大文字(26)と、アルファベット小文字or大文字に続いて[e,r,t]((26x2)x3=156) アルファベット小文字に続いて n (52)。n だけ大文字との組み合わせ変数が無い。意味深。全部使うのかな?この変数たち。 | |||
うち、Sn と i は使われていた。 | |||
<syntaxhighlight lang="javascript"> | |||
Sn:Sn(t, e) { | |||
(null == e || e > t.length) && (e = t.length); | |||
for(var r = 0, n = new Array(e); r < e; r++) | |||
n[r] = t[r]; | |||
return n | |||
} | |||
</syntaxhighlight> | |||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
i:i(t, e) { | |||
(null == e || e > t.length) && (e = t.length); | |||
for(var r = 0, n = new Array(e); r < e; r++) | |||
n[r] = t[r]; | |||
return n | |||
} | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
だけ、定義済みでした。まったく同じ関数。 | |||
この関数が呼ばれるときの t は、 | |||
t:(30) ['[tex]/action', '[tex]/ams', '[tex]/amscd', '[tex]/bbox', '[tex]/boldsymbol', '[tex]/braket', '[tex]/bussproofs', '[tex]/cancel', '[tex]/centernot', '[tex]/color', '[tex]/colortbl', '[tex]/configmacros', '[tex]/enclose', '[tex]/extpfeil', '[tex]/html', '[tex]/mathtools', '[tex]/mhchem', '[tex]/newcommand', '[tex]/noerrors', '[tex]/noundefined', '[tex]/physics', '[tex]/require', '[tex]/setoptions', '[tex]/tagformat', '[tex]/textcomp', '[tex]/textmacros', '[tex]/unicode', '[tex]/verb', '[tex]/cases', '[tex]/empheq'] | |||
で、e は undefined だから e は t の配列の要素数(30)になります。n は 要素数30の配列になって、r が 0 から 29 まで変動して、n[r] = r[r]; なので配列のコピーですね。コピーした n を返します。 | |||
何やってるか、想像がつきそうなのが2個3個あればいいな。 | |||
=== __webpack_modules__[ | === __webpack_modules__[9515].call(r.exports, r, r.exports, __webpack_require__) === | ||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
9515: function(t, e, r) { | |||
var n = this && this.__values || function(t) { | |||
var e = "function" == typeof Symbol && Symbol.iterator, | |||
r = e && t[e], | |||
n = 0; | |||
if(r) return r.call(t); | |||
if(t && "number" == typeof t.length) return { | |||
next: function() { | |||
return t && n >= t.length && (t = void 0), { | |||
value: t && t[n++], | |||
done: !t | |||
} | |||
} | |||
}; | |||
throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.") | |||
}; | |||
Object.defineProperty(e, "__esModule", { | |||
value: !0 | |||
}), e.MathJax = e.combineWithMathJax = e.combineDefaults = e.combineConfig = e.isObject = void 0; | |||
var o = r(3282); | |||
function i(t) { | |||
return "object" == typeof t && null !== t | |||
} | |||
function s(t, e) { | |||
var r, o; | |||
try { | |||
for(var a = n(Object.keys(e)), l = a.next(); !l.done; l = a.next()) { | |||
var c = l.value; | |||
"__esModule" !== c && (!i(t[c]) || !i(e[c]) || e[c] instanceof Promise ? null !== e[c] && void 0 !== e[c] && (t[c] = e[c]) : s(t[c], e[c])) | |||
} | |||
} catch(t) { | |||
r = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
l && !l.done && (o = a.return) && o.call(a) | |||
} finally { | |||
if(r) throw r.error | |||
} | |||
} | |||
return t | |||
} | |||
e.isObject = i, e.combineConfig = s, e.combineDefaults = function t(e, r, o) { | |||
var s, a; | |||
e[r] || (e[r] = {}), e = e[r]; | |||
try { | try { | ||
l && ! | for(var l = n(Object.keys(o)), c = l.next(); !c.done; c = l.next()) { | ||
var u = c.value; | |||
i(e[u]) && i(o[u]) ? t(e, u, o[u]) : null == e[u] && null != o[u] && (e[u] = o[u]) | |||
} | |||
} catch(t) { | |||
s = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
c && !c.done && (a = l.return) && a.call(l) | |||
} finally { | |||
if(s) throw s.error | |||
} | |||
} | } | ||
return e | |||
}, e.combineWithMathJax = function(t) { | |||
return s(e.MathJax, t) | |||
}, void 0 === r.g.MathJax && (r.g.MathJax = {}), r.g.MathJax.version || (r.g.MathJax = { | |||
version: o.VERSION, | |||
_: {}, | |||
config: r.g.MathJax | |||
}), e.MathJax = r.g.MathJax | |||
}, | |||
</syntaxhighlight> | |||
なかなかわけわからん。 | |||
<syntaxhighlight lang="javascript" inline> | |||
var n = this && this.__values || function(t){…} | |||
</syntaxhighlight> | |||
グローバルオブジェクトだからthisはWindowオブジェクトなんだけど、strictモードなので、. の前が省略されているので、undefined だね。だから、値だけを取り出す、this.__values も undefined。n は function(t) があるから true かな。論理演算している意味が謎だわ。何がしたいんだろう。ま、あとあと何回か呼び出されるんだろうと思って、ブレークポイントを設定したら、謎のコードが33回呼ばれる。おいかけきれるかこれ? t には何かのキーワードみたいなのが入って呼ばれるね。呼び出されるときの t の値を記録してみるか。 | |||
'''追記※1 : やっぱり論理演算にはJavaScript特有の動作がありました。論理和の場合は、左から0 や null や undefinedのような値が続いて、一番最初に左側に現れた値をそのまま返すんだそうな。なので、最初の値がオブジェクトや関数や変数ならばそのまま、その値が返るそうです。論理積の場合は左側に 1 や true がある場合は最初のオブジェクト値や関数や変数値がかえるそうなのです。''' | |||
エグイ仕様だな。もう比較する必要ないね。みたいなサバサバ系の処理だ。これは専門家じゃないとむずいな。JavaScript末恐ろしい。自分なんかは知らないことだらけなんじゃね。と、思えてきた。深い!JavaScript。勉強しがいがある! 追記※1ここまで。 | |||
1回目 (10) ['paths', 'source', 'dependencies', 'provides', 'load', 'ready', 'failed', 'require', 'pathFilters', 'versionWarnings'] | |||
2回目 ( 1) ['loader'] | |||
3回目 ( 9) ['input', 'output', 'handler', 'adaptor', 'document', 'elements', 'typeset', 'ready', 'pageReady'] | |||
4回目 ( 2) ['startup', 'options'] | |||
5回目 ( 2) ['startup', 'options'] | |||
6回目 (1) ['_'] | |||
7回目 (1) ['components'] | |||
8回目 (37) ['a11y/semantic-enrich', 'a11y/complexity', 'a11y/explorer', '[mml]/mml3', '[tex]/all-packages', '[tex]/action', '[tex]/autoload', '[tex]/ams', '[tex]/amscd', '[tex]/bbox', '[tex]/boldsymbol', '[tex]/braket', '[tex]/bussproofs', '[tex]/cancel', '[tex]/centernot', '[tex]/color', '[tex]/colorv2', '[tex]/colortbl', '[tex]/configmacros', '[tex]/enclose', '[tex]/extpfeil', '[tex]/html', '[tex]/mathtools', '[tex]/mhchem', '[tex]/newcommand', '[tex]/noerrors', '[tex]/noundefined', '[tex]/physics', '[tex]/require', '[tex]/setoptions', '[tex]/tagformat', '[tex]/textcomp', '[tex]/textmacros', '[tex]/unicode', '[tex]/verb', '[tex]/cases', '[tex]/empheq'] | |||
9回目 (3) ['tex', 'mml', 'sre'] | |||
10回目 (4) ['startup', 'input/tex', 'input/tex-full', '[tex]/all-packages'] | |||
11回目 (4) ['[tex]/amsCd', '[tex]/colorV2', '[tex]/configMacros', '[tex]/tagFormat'] | |||
12回目 (1) ['_'] | |||
13回目 (6) ['adaptors', 'components', 'core', 'handlers', 'mathjax', 'util'] | |||
14回目 (1) ['global'] | |||
15回目 (1) ['_'] | |||
16回目 (1) ['input'] | |||
17回目 (1) ['_'] | |||
18回目 (1) ['input'] | |||
19回目 (2) ['mathml_ts', 'mathml'] | |||
20回目 (1) ['_'] | |||
21回目 (1) ['output'] | |||
22回目 (1) ['checkReady'] | |||
23回目 (1) ['_'] | |||
24回目 (1) ['output'] | |||
25回目 (2) ['chtml', 'common'] | |||
26回目 (1) ['fonts'] | |||
27回目 (1) ['fonts'] | |||
28回目 (1) ['fontURL'] | |||
29回目 (1) ['font'] | |||
30回目 (1) ['_'] | |||
31回目 (1) ['ui'] | |||
32回目 (1) ['_'] | |||
33回目 (1) ['a11y'] | |||
呼ばれるのは、この9515をコールしたときではなく、後で、違う方法で実行されるように呼ばれるようだ。そのときに、このような引数が渡されて実行される。でも、デバッガによると n には、この関数全体が格納される。おそらく n によってこの関数が実行されるんだろう。論理演算ってそういう解釈があるんだなとは疑問に思いつつも納得しようと思う。調べないとな。33回も呼ばれるんだから、後で、こんなのあったなぁってなるんだろう。先に進もう。 | |||
次に実行されるのは<syntaxhighlight lang="javascript" inline>Object.defineProperty(e, "__esModule", { value: !0 | |||
})</syntaxhighlight>で、Object.defineProperty()はオブジェクトの定義をする命令で、第一引数のオブジェクトに、第二引数のメンバ変数に第三引数を値として設定している。つまり、<syntaxhighlight lang="javascript" inline>e.__esModule = {value : !0} </syntaxhighlight>としている。なんで!0なんだろう。!0 って true のことだと思うので、<syntaxhighlight lang="javascript" inline>e.__esModule = {value : true} </syntaxhighlight>って感じだと思う。 __esModule は、EcmaScriptに準拠したモジュールかを設定しているとか説明があった。変数 e の扱いを決定するものだな。でも、<syntaxhighlight lang="javascript" inline> e.__esModule = true </syntaxhighlight> じゃなくて<syntaxhighlight lang="javascript" inline> {value : true}</syntaxhighlight> なんだな。 | |||
続けて、xxx = void 0;を設定という形式で | |||
e.MathJax = undefined; | |||
e.combineWithMathJax = undefined; | |||
e.combineDefaults = undefined; | |||
e.combineConfig = undefined; | |||
e.isObject = undefined; | |||
としている。e は、どうやら環境変数って意味っぽいな Environments の e だな。MathJax は、このプログラムの核となる設定でcombineは結合とか混合って意味でwithMathJaxはMathJaxと結合するもの。Defaults規定値で結合するもの。Configは設定で結合するもの、isObjectはオブジェクトかどうか。って感じかな。ひとつ感じるのは、まだ何も始まってすらいないという感じだな。これだけおおがかりなことやっていながら、設定するのは、undefined だもんな。 | |||
次は <syntaxhighlight lang="javascript" inline> var o = r(3282); </syntaxhighlight>が実行されます。rは関数が格納されていて、__webpack_require__です。いやはや、この__webpack_require__(9515)を通じて、__webpack_modules__[9515].call()がされて今にいたっているのに、それが終わるのを待たずして、関数の内で、また新しく__webpack_require__(3282)を実行するようなものですね。確か、この__webpack_require__(9515)の後も同じように__webpack_require__(3282)が実行される流れになっていたような。ここでも実行しようとするんだね。3282は関数の内容が少ない。 | |||
o = { VERSION: "3.2.2", __esModule : true } になる。でも、次に呼ばれる__webpack_require__(3282)の結果は e 配列に追加格納されるような。さっき環境変数の e にいくつかundefined値が設定されたものもあったな。そして o にも同じような値を持たせるんだな。今、結構1文字の変数埋まってきてるな。環境変数っぽい e 。今しがた論理演算で込みなのに取得された n 。そして、o 。それから__webpack_require__が格納された r 。9515のcall内での t は <s>r.export</s> <span style="color:red;">r</span> という引数で{ Exports : {} }に対応する。eは r.Exportsの{}に対応しているがeには値が設定されてExports値の中身が増えていくはず。呼ばれる前は t は配列番号の9515を保持するモノとして使われていた。 | |||
この後、さらに2つの1文字変数に関数が格納されます。 | |||
i 短い関数<syntaxhighlight lang="javascript" inline> function i(t) { return "object" == typeof t && null !== t } </syntaxhighlight>、そして s には割かし長めの関数が<syntaxhighlight lang="javascript" inline> function s(t, e) { … } </syntaxhighlight>。 | |||
そして今しがた獲得したiとsの関数をちょっと前に登場した環境変数に格納する。グローバル系の処理が多いね。これって、なんか違うjava Scriptを同時に動かしているsiteなら、変数が重複して動かなくなりそうなもんだけど大丈夫なのかな。 | |||
e.isObject = i; | |||
e.combineConfig = s; | |||
に格納している。確かにe.isObject(t)は動かすと、t がオブジェクトなのかを識別して、オブジェクトなら1と返却するし、違うなら0になるね。combineConfig は長いよね。簡単にながめてみると。 | |||
関数 s は for文で 論理演算の元で格納された関数 n に引数 o を与えながら全ての o の要素分だけ繰り返す。o は Version と __esModuleだけだし、たいした繰り返し処理ではなさそうだ。それよか、この for 文がエグイ記述だな。 | |||
<syntaxhighlight lang="javascript" inline>var a = n(Object.keys(e)), l = a.next(); !l.done; l = a.next()</syntaxhighlight> | |||
ということなんだけど、初期値がカンマ区切りで2個設定されている <syntaxhighlight lang="javascript" inline>l = a.next() </syntaxhighlight>は次の値なのかな。繰り返し条件の <syntaxhighlight lang="javascript" inline>!l.done</syntaxhighlight> だから、<syntaxhighlight lang="javascript" inline>l.done</syntaxhighlight> が 0 の間は、<syntaxhighlight lang="javascript" inline>!l.done</syntaxhighlight> が 1 なので、繰り返す。<syntaxhighlight lang="javascript" inline>l.done</syntaxhighlight> が 1 なら終了で、増分は <syntaxhighlight lang="javascript" inline>l= a.next</syntaxhighlight> で次の配列値が l に入るみたいな感じだな。 ややこしい。e の配列には今は以下の通りになっていて、順番に実行されるのかな。 | |||
e.MathJax = undefined; | |||
e.combineWithMathJax = undefined; | |||
e.combineDefaults = undefined; | |||
e.combineConfig = s; | |||
e.isObject = i; | |||
こんな感じの環境変数のキーを一個づつ a に取得 l には次の値。繰り返したい要素 2つの値を同時に処理できるというのは斬新だけどやりたい処理ってのは c には 次のキー値 l.value の値が入りつつ、論理演算で、__esModuleという文字列値でないときにtrueである且つ、<syntaxhighlight lang="javascript" inline>e[c] instanceof Promise ? null !== e[c] && void 0 !== e[c] && (t[c] = e[c]) : s(t[c], e[c])</syntaxhighlight>?instanceof Promise?ムズッ。Promiseってのは非同期・同期処理についてキャストできたかというのを判定する処理らしい。なんだよ非同期とか同期とか。関数によっては時間がかかるものとかは、順番に処理されることなく、次々と時間がかからない処理を進めていく。非同期。それを順番に処理するのは、同期処理。と言っていると思います。Promiseは処理をするタイミングを調整するものです。そういった関数であるかどうかを判定しているらしい。いづれにしても何がしたいのかわからない。論理演算だけをして、特に代入することもないという。わからん。e[c] instanceof Promiseの結果が true なら null !== e[c] && void 0 !== e[c] && (t[c] = e[c]) で false ならs(t[c], e[c])で、再帰処理がされる。いやそもそも i(t[c]) とか i(e[c]) とか t[c] とか e[c] とか なんだろうね。i(…) は引数がオブジェクトかどうかを判定する関数でした。cは、 MathJax/combineWithMathJax/combineDefaults/combineConfig/isObject/…esModule/で終了条件にesModuleというキーが使われている予感。他のものの場合は、それがオブジェクトなのかを判断するi(e[c])。t[c]。おいておくか。ちょろっとここにブレークポイントを設定してどういうものが実行されるかみてみてみましょう。 | |||
実行されるときには t の内容は以下のような値になっているようです。 | |||
{version: '3.2.2', _: {}, config: {paths: {mathjax: 'h<span>tt</span>p://localhost:5500/es5'}, source: {}, dependencies: {}, provides: { }, load: Array(0), …}} | |||
}, | |||
</ | |||
eは{loader: {versions: Map(0), ready: ƒ, load: ƒ, preLoad: ƒ, defaultReady: ƒ, …}}で、a = n(Object.key(e)) の a はn('loader')になります。nはちょっと前にあった関数が入っていて、 | |||
<syntaxhighlight lang="javascript"> | |||
function(t /* ← 'loader' */) { | |||
var e = "function" == typeof Symbol && Symbol.iterator, | |||
r = e && t[e],/* e : Symbol(Symbol.iterator) && 'loader'[Symbol(Symbol.iterator)] → r : ƒ values() */ | |||
n = 0; | |||
if(r) return r.call(t); /* r = function( t /='loader'=/ ){return t /='loader'=/ } → return 'loader' */ | |||
if(t && "number" == typeof t.length) return { | |||
next: function() { | |||
return t && n >= t.length && (t = void 0), { | |||
value: t && t[n++], | |||
done: !t | |||
} | |||
} | |||
}; | |||
throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.") | |||
} | |||
</syntaxhighlight> | |||
でした。この t が'loader'ってことですね。 l は { value: "loader", done: false, } になります。for文の中身の | |||
<syntaxhighlight lang="javascript" inline>var a = n(Object.keys(e)), l = a.next(); !l.done; l = a.next()</syntaxhighlight> | |||
この l です。a は {} です。Array Iterator と表現されます。このfor文の使い方は難しい。理解できない。lの中身がそうなる理由が見えてこない。初期値は長い関数によって帰ってくる値で n('loader') の結果が {} で、l = a.next() なんだけど、{ value: "loader", done: false, }っつうね。終了条件の l.done がどこからきたかはわかっていないけど、最初は false なので 1回は処理されるというね。で、おわるとl = a.next() が実行されて次の処理になる。 | |||
c = l.Value は最初は 'loader' | |||
t[c] = undefined | |||
e[c] = {versions: Map(0), ready: ƒ, load: ƒ, preLoad: ƒ, defaultReady: ƒ, …} これは e['loader']の値です。 | |||
e[c] instanceof Promise : false | |||
falseなので、再帰部分が呼ばれる。s(t[c], e[c])。ふむ。いずれにしても、ここでは論理式が書かれているだけで、処理はなにもされなくて、これがエラーにならないかどうかを確かめているだけなのだろう。何もなければ、t そのものが返却される。うまくいかないとエラーになる。 | |||
c はこの後 'loader' → 'versions' → 'ready' → 'load' → 'preLoad' → 'defaultReady' → 'getRoot' → 'pathFilter' → 'item' → '0' → 'item' → … になる。 | |||
こんな、調子だとわからないことだらけだな! | |||
なんしか、e.combineDefaults = function t(e, r, o) { … } もおなじような試みの関数が設定される。 | |||
e.combineDefaults = t; また t が使われた。 | |||
e.combineConfig = s; | |||
e.isObject = i; | |||
次に、<syntaxhighlight lang="javascript" inline>e.combineWithMathJax = function(t) { return s(e.MathJax, t) }</syntaxhighlight>が設定される。あ!!あー!これ今作ったばっかりの関数 s が呼ばれてる!でも、実行されるのはもっと後だな。でも引数は e.MathJax, t だ。s(t, e)だからな。でも、t が e.MathJax で、 e が t か。また t が引数。このときの t は <syntaxhighlight lang="javascript" inline>{'loader' : {versions: Map(0), ready: ƒ, load: ƒ, preLoad: ƒ, defaultReady: ƒ, this : {} }} </syntaxhighlight>みたいな値です。 | |||
<syntaxhighlight lang="javascript"> | |||
void 0 === r.g.MathJax && (r.g.MathJax = {}), | |||
r.g.MathJax.version || ( | |||
r.g.MathJax = { | |||
version: o.VERSION, | |||
_: {}, | |||
config: r.g.MathJax | |||
} | |||
), | |||
e.MathJax = r.g.MathJax | |||
</syntaxhighlight> | |||
あーそうか。呼び出される前に、var r =__webpack_module_cache__[t] = { exports: {} };処理やってるから2回目は、少なくともexportsの空の値に e 返す。っていう処理になるんだな。この後 3282 。で呼ばれても、同じ処理をするわけではないんだな。 | |||
=== __webpack_modules__[3282].call(r.exports, r, r.exports, __webpack_require__) === | |||
<syntaxhighlight lang="javascript"> | |||
3282: function(t, e) { | |||
Object.defineProperty(e, "__esModule", { | |||
value: !0 | |||
}), e.VERSION = void 0, e.VERSION = "3.2.2" | |||
}, | |||
</syntaxhighlight> | |||
9515の中のoに設定したのと同じ要領で、e に設定するのかと思いきや、知らぬ間に __webpack_module_cache__ に{ 3282 : Exports : { version : '3.2.2', __esModule : true }, 9515 : {isObject: ƒ, combineConfig: ƒ, combineDefaults: ƒ, combineWithMathJax: ƒ, MathJax: {…}, …} }ってのが出来上がってた。だから、3282は __webpack_module__[3282]は呼ばれず、__webpack_module_cache__[3282]のreturn で e.Exports = { version : '3.2.2', __esModule : true } が返却される。つまり実行済みだからもう一度やり直しにはならない。__webpack_module_cache__ は優秀な仕組み。9515でいろいろやっている内に設定されたのは自分の知能不足。__webpack_modules__のcallは、最初の一つ目の引数は呼ばれた関数のthisになるオブジェクトを指定している。その後に最大3つの引数が設定されていて、t = r, e = r.Exports, n = __webpack_require__ として処理されることは覚えておいてよいね。r に何が設定されているかで、処理が決まるといってもいい。そして、どこで r や r.Exports が変化するかを抑えないと駄目だ。このあたりがこのプログラムを理解するうえで重要そうだ。 | |||
=== __webpack_modules__[235].call(r.exports, r, r.exports, __webpack_require__) === | |||
<syntaxhighlight lang="javascript"> | |||
235: function(t, e, r) { | |||
var n, o, i = this && this.__values || function(t) { | |||
var e = "function" == typeof Symbol && Symbol.iterator, | |||
r = e && t[e], | |||
n = 0; | |||
if(r) return r.call(t); | |||
if(t && "number" == typeof t.length) return { | |||
next: function() { | |||
return t && n >= t.length && (t = void 0), { | |||
value: t && t[n++], | |||
done: !t | |||
} | |||
} | |||
}; | |||
throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.") | |||
}; | |||
Object.defineProperty(e, "__esModule", { | |||
value: !0 | |||
}), e.CONFIG = e.MathJax = e.Loader = e.PathFilters = e.PackageError = e.Package = void 0; | |||
var s = r(9515), | |||
a = r(265), | |||
l = r(265); | |||
} | Object.defineProperty(e, "Package", { | ||
enumerable: !0, | |||
get: function() { | |||
return l.Package | |||
} | |||
}), Object.defineProperty(e, "PackageError", { | |||
enumerable: !0, | |||
get: function() { | |||
return l.PackageError | |||
} | |||
}); | |||
var c, u = r(7525); | |||
if( | |||
e.PathFilters = { | |||
source: function(t) { | |||
return e.CONFIG.source.hasOwnProperty(t.name) && (t.name = e.CONFIG.source[t.name]), !0 | |||
}, | |||
normalize: function(t) { | |||
var e = t.name; | |||
return e.match(/^(?:[a-z]+:\/)?\/|[a-z]:\\|\[/i) || (t.name = "[mathjax]/" + e.replace(/^\.\//, "")), t.addExtension && !e.match(/\.[^\/]+$/) && (t.name += ".js"), !0 | |||
}, | |||
prefix: function(t) { | |||
for(var r; | |||
(r = t.name.match(/^\[([^\]]*)\]/)) && | |||
e.CONFIG.paths.hasOwnProperty(r[1]); | |||
) | |||
t.name = e.CONFIG.paths[r[1]] + t.name.substr(r[0].length); | |||
return !0 | |||
} | |||
}, | |||
function(t) { | |||
var r = s.MathJax.version; | |||
t.versions = new Map, | |||
t.ready = function() { | |||
for(var t, e, r = [], n = 0; n < arguments.length; n++) r[n] = arguments[n]; | |||
0 === r.length && (r = Array.from(a.Package.packages.keys())); | |||
var o = []; | |||
try { | |||
for(var s = i(r), l = s.next(); !l.done; l = s.next()) { | |||
var c = l.value, | |||
u = a.Package.packages.get(c) || new a.Package(c, !0); | |||
o.push(u.promise) | |||
} | |||
} catch(e) { | |||
t = { | |||
error: e | |||
} | |||
} finally { | |||
try { | |||
l && !l.done && (e = s.return) && e.call(s) | |||
} finally { | |||
if(t) throw t.error | |||
} | |||
} | |||
return Promise.all(o) | |||
}, | |||
t.load = function() { | |||
for(var r, n, o = [], s = 0; s < arguments.length; s++) | |||
o[s] = arguments[s]; | |||
if(0 === o.length) | |||
return Promise.resolve(); | |||
var l = [], | |||
c = function(r) { | |||
var n = a.Package.packages.get(r); | |||
n || | |||
(n = new a.Package(r)).provides(e.CONFIG.provides[r]), | |||
n.checkNoLoad(), | |||
l.push(n.promise.then( | |||
( | |||
function() { | |||
e.CONFIG.versionWarnings && | |||
n.isLoaded && | |||
!t.versions.has(a.Package.resolvePath(r)) && | |||
console.warn("No version information available for component ".concat(r)) | |||
} | |||
) | |||
) | |||
) | |||
}; | |||
try { | |||
for(var u = i(o), p = u.next(); !p.done; p = u.next()) { | |||
var h = p.value; | |||
c(h) | |||
} | |||
} | |||
catch(t) { | |||
r = { error: t } | |||
} | |||
finally { | |||
try { | |||
p && !p.done && (n = u.return) && n.call(u) | |||
} | |||
finally { | |||
if(r) | |||
throw r.error | |||
} | |||
} | |||
return a.Package.loadAll(), Promise.all(l) | |||
}, | |||
t.preLoad = function() { | |||
for(var t, r, n = [], o = 0; o < arguments.length; o++) | |||
n[o] = arguments[o]; | |||
try { | |||
for(var s = i(n), l = s.next(); !l.done; l = s.next()) { | |||
var c = l.value, | |||
u = a.Package.packages.get(c); | |||
u || (u = new a.Package(c, !0)).provides(e.CONFIG.provides[c]), u.loaded() | |||
} | |||
} | |||
catch(e) { | |||
t = { error: e } | |||
} | |||
finally { | |||
try { | |||
l && !l.done && (r = s.return) && r.call(s) | |||
} | |||
finally { | |||
if(t) | |||
throw t.error | |||
} | |||
} | |||
}, | |||
t.defaultReady = function() { | |||
void 0 !== e.MathJax.startup && e.MathJax.config.startup.ready() | |||
}, | |||
t.getRoot = function() { | |||
var t = "//../../es5"; | |||
if("undefined" != typeof document) { | |||
var e = document.currentScript || document.getElementById("MathJax-script"); | |||
e && (t = e.src.replace(/\/[^\/]*$/, "")) | |||
} | |||
return t | |||
}, | |||
t.checkVersion = function(n, o, i) { | |||
return t.versions.set(a.Package.resolvePath(n), r), | |||
!(!e.CONFIG.versionWarnings || o === r) && (console.warn("Component ".concat(n, " uses ").concat(o, " of MathJax; version in use is ").concat(r)), !0) | |||
}, | |||
t.pathFilters = new u.FunctionList, | |||
t.pathFilters.add(e.PathFilters.source, 0), | |||
t.pathFilters.add(e.PathFilters.normalize, 10), | |||
t.pathFilters.add(e.PathFilters.prefix, 20) | |||
} | |||
(c = e.Loader || (e.Loader = {})), | |||
e.MathJax = s.MathJax, | |||
void 0 === e.MathJax.loader /*だいぶ前のif文の比較演算子の対象。カンマ構文の最後*/ | |||
) | |||
{ /* e.MathJax.loader が undefined のときの処理 */ | |||
( 0, s.combineDefaults )( /* s.combineDefaults メンバ関数の引数開始 */ | |||
e.MathJax.config, | |||
"loader", | |||
{ | |||
paths: { | |||
mathjax: c.getRoot() | |||
}, | |||
source: {}, | |||
dependencies: {}, | |||
provides: {}, | |||
load: [], | |||
ready: c.defaultReady.bind(c), | |||
failed: function(t) { | |||
return console.log("MathJax(" . concat(t.package || "?", "): ") . concat(t.message)) | |||
}, | |||
require: null, | |||
pathFilters: [], | |||
versionWarnings: !0 | |||
} | |||
), | |||
(0, s.combineWithMathJax)( /* combineWithMathJax メンバ関数の引数開始 */ | |||
{ | |||
loader: c | |||
} | |||
); //長かったカンマ構文終わり。 | |||
try { | |||
for(var p = i(e.MathJax.config.loader.pathFilters), h = p.next(); !h.done; h = p.next()) { | |||
var f = h.value; | |||
Array.isArray(f) ? c.pathFilters.add(f[0], f[1]) : c.pathFilters.add(f) | |||
} | |||
} | |||
} | catch(t) { | ||
n = { error: t } | |||
} | |||
finally { | |||
try { | |||
h && !h.done && (o = p.return) && o.call(p) | |||
} | |||
finally { | |||
if(n) | |||
throw n.error | |||
} | |||
} | |||
} | |||
e.CONFIG = e.MathJax.config.loader | |||
}, | |||
</syntaxhighlight> | </syntaxhighlight> | ||
ここでも9515とよく似た処理がされるね。t = r.Exports ⇔ {exports: {…}, undefined: undefined}, e = r ⇔ {}, r = r.Exports ⇔ ƒ __webpack_require__(t) { … } の3つの引数が使われる。引数の対応すら違っているな、<syntaxhighlight language="javascript" inline>__webpack_modules__[t].call(r.exports, r, r.exports, __webpack_require__)</syntaxhighlight> | |||
ん?あ、callの処理を勘違いしているんだな。ちょっと調べてみる。おー。第一引数は呼び出した関数のthisとなるものらしい。nullとundefined(void 0)を設定すると、グローバルのthisになってWindowオブジェクトが返ってくるんだそうな。今回の場合はr.exportsがthisってことだな。なので、t = r ⇔ {exports: {…}, undefined: undefined}, e = r.exports ⇔ {}, r = __webpack_require__ ⇔ ƒ __webpack_require__(t) { … } ってことだ。おーちょっと解決。勘違い恐るべし。 | |||
t は this。e は Environments。r は result という意味かな? r.Exports を 格納する result。 | |||
= | 以下のような値が設定されます。 | ||
e.CONFIG = undefined; | |||
e.MathJax = undefined; | |||
e.Loader = undefined; | |||
e.PathFilters = undefined; | |||
e.PackageError = undefined; | |||
e.Package = undefined; | |||
そして、 | |||
var s = r(9515);{isObject: ƒ, combineConfig: ƒ, combineDefaults: ƒ, combineWithMathJax: ƒ, MathJax: {version: '3.2.2', _: {…}, config: {…}}} | |||
var a = r(265); {PackageError: ƒ, Package: ƒ, __esModule: true} | |||
var l = r(265); {PackageError: ƒ, Package: ƒ, __esModule: true} | |||
の結果をs, a, l にそれぞれ格納。 | |||
r() で その時点で Exports されている値が取得できるんだね。 | |||
Object.defineProperty で e.Packageとe.PackageErrorに値と関数を設定。 | |||
<syntaxhighlight lang="javascript"> | |||
{ | |||
enumerable : true | |||
get : function() { return l.Package (※e.PackageErrorはl.PackageError) } | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
そして | |||
var u = r(7525); {FunctionList: ƒ, __esModule: true} | |||
の結果を u に格納。 | |||
次に無駄に長い if 文。カンマ区切り構文が続く、評価されるのは一番最後(右側)の値。e.PathFilters={source:function(t){},normalize:function(t){},prefix:function(t){}},…まだ続く。 | |||
まずはキー source からで e.CONFIG.source.hasOwnProperty(t.name) で t.name を作り、 t.name = e.CONFIG.source[t.name]を設定し、常に!0つまりtrueを返却するキー名sourceの値に結び付いた関数。 | |||
normalize は t.nameがパターンマッチで、/^(?:[a-z]+:\/)?\/|[a-z]:\\|\[/i つまり、先頭が(?:[a-z]+:\/)で始まるかを判定。例えばc:abcd:\やc:abcd:abcd:abcd:\みたいに:で始まって、aからzのアルファベットの連続があったあとに来て:\で閉じられるものもしくは、先頭からじゃなくても、aからzの1文字:\もしくは [ があるかを判定。i オプションなので大文字と小文字の区別をしないというマッチングになります。おそらくドライブ文字のようなものにマッチングしようとしていると推測されます。"[mathjax]/" + e.replace(/^\.\//, "") は、t.name の値として [mathjax]/を先頭に付け足して、最初の./を取っ払ったものに置換しています。末尾が ./**** に一致しなければ、.jsを付け足す。という処理をするようです。先に ./ があったら取っ払っていますので、拡張子が既につけられていないことを確認しているものですね。一行でやりたいことをまとめれるって素敵ですね。自分だったらもっと何段階かにわけないと駄目だな。で、見てみたんですけど、e は startup のとき t は { name: '[mathjax]/startup.js', original: 'startup', addExtension: true} となり、startup を [mathjax]/startup.js に置換・格納する処理になっています。 | |||
prefixはfor文の終了条件でパターンマッチングし [] の中が先頭から ] 以外の文字で最長マッチングした値を r[1] に取得。ようするに[]の中の文字列を r へ格納して、マッチングの結果 r[1] という名前のメンバがある限り繰り返し処理。r[0]には[xxxx]のように最長マッチングが取得できて、要するに r[0] は [] 付き、r[1] は [] 無しの文字列が取得できる。[] 無しの文字列をプログラム中では prefix プレフィックス:接頭辞と呼んでいるようで、その終わる部分の長さ以降からの文字を e.config.path['mathjax']の値、つまり h<span>tt</span>p://localhosts:5500/es5 の後ろに startup.js 付け足す処理をします。 | |||
< | |||
ふむー。具体的に何をするんだろうな。先頭から追っていくと、何に使われるかわからない関数の準備ばっかりになるんだろうか。すさまじいコード量だ。作った人すげー。日々、痛感させられる。自分は何かここまで頑張りとおしたことはあるだろうかと、過去への振り返りさえ発生する。見習いたいものだ。 | |||
とはいいつつも次の関数定義もざっと見ておく。 | |||
次の関数は割かし眺めだ。しかもやっぱりわけがわからない。こういうときは動かしてみてどうなるか見てみる。ひとついえるのは動かしてみてとはいうものの、この関数が呼ばれる保証はない。ただ、まだ前半なのプログラムの根幹をなす関数を定義している気がする。 | |||
動かすと t の値が {versions: Map(0) {size: 0}, ready: ƒ, load: ƒ, preLoad: ƒ, defaultReady: ƒ} こうなった。Version Map0とは?配列の便利なタイプがMapというものらしく、.set('xxx',{yyy:xxx,zzz:xxx}) や .get('xxx') や .has('xxx') といったメソッドや.size といったものがあります。Version番号くらいしか設定されないところに Map というのが不可解なくらいですね。あとは、動作した後に中々、多くの関数が定義されたなという印象。あとはカンマ構文は、セミコロンにできるだけ焼き直した方がデバッグしやすいけど、うかつに分解すると不具合が発生する元にもなるという諸刃の剣。でもちょっと分解しないとデバッグしておいかけにくい。自分みたいな素人が改造して使わないようにデバッグしにくいようにしてるんだろうなぁ。 | |||
さっそく、このあたりの定義されるだけの関数の中のプログラムにブレークポイントを設定してみました。一番最初に呼ばれたのは、t.getRoot の部分です。ふむ。なにげに気になっていた部分 //../../es5/とハードコーディングされているパスがあるが、MathJaxはどこにあるhtmlから呼ばれるかわからない構造のはずだし、このtex-mml-chtml.jsファイル自体からのパスだとしてもそんなところにはes5はない。おー。すぐに t は上書きされますね。 document.getElementById("MathJax-script") = null で e = document.currentScript で e.src は h<span>tt</span>p://localhost:5500/es5/tex-mml-chtml.js になりました。そうすると。これの e.src.replace(/\/[^\/]*$/, "") は h<span>tt</span>p://localhost:5500/es5/ です。/[/以外]末尾 で末尾の / から以外っていみで、後ろのファイル名が取り除かれた名前になります。t.getRoot に h<span>tt</span>p://localhost:5500/es5/ がセットされます。 おー。やるなMathJax。 | |||
</ | |||
次に呼ばれたのは、t.preload です。o < Argument.length の間、繰り返します。Argument は 大きさ9の要素になっています。2つの連想配列があります。キーはcalleeとSymbol(Symbol.iterator)です。Arguments(9) ['loader', 'startup', 'core', 'input/tex', 'input/mml', 'output/chtml', 'output/chtml/fonts/tex.js', 'ui/menu', 'a11y/assistive-mml', callee: <accessor>, Symbol(Symbol.iterator): ƒ] で、繰り返し処理によってn[0]~n[8]の9個が Argument からコピーされます。 | |||
<syntaxhighlight lang="javascript"> | |||
e.CONFIG = | |||
( | { | ||
paths : {mathjax: 'http://localhost:5500/es5'}, | |||
failed : { ƒ (t) { | |||
\treturn console.log("MathJax(" . concat(t.package || "?", "): ") . concat(t.message)) | |||
} | |||
}, | |||
source : {…}, | |||
dependencies : {…}, | |||
provides : {…}, | |||
load : Array(0), | |||
versionWarnings : true | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
やっぱり、for文に.next()が使われるパターンの深い理解が必要だな。かなりの頻度で使われる。ふむ[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Generator/next https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Generator/next] によると、next()を使うと、value 実際に使いたい次々に取り出す配列値 と done 終了フラグ を返すそうな。終わったら true だそうです。 | |||
<syntaxhighlight lang="javascript" inline>for(var arraydata = arrayobject, countobject = arraydata.next(); !countobject.done; countobject = arraydata.next()){ … ; var contentvalue= countobject.value; … }</syntaxhighlight> | |||
for文はこの形式で構成されます。初期値の処理が二つになります。配列や連想配列構造のオブジェクトarrayobjectをarraydataに受け取り、この値に対してarraydata.next()を呼び出すたびに次の配列値へと移動しますが、最初の値の取り出しでもarraydata.next()が必要なので、実行して、実際に使う変数値として、countobject に保持させます。これがfor文の初期動作です。終了条件は、実際に使う値の countobject のメンバ関数 done(ダン) を監視すればよいことになります。最後の値を処理したら、true になります。なので、終了条件は !countobject.done となります。そして、次の値を実際に使用する変数 countobject に代入しつつも、arraydata.next() を呼び出せばいいです。for文の中では実際に使う値を、contentvalue = countobject.valueのように取り出すことをするでしょう。実際、mathjax でも、実にオーソドックスに配列の値を使ったfor文を処理しています。一方で、もうちょっと変わった連想配列の繰り返し処理中で特殊なfor文(for of:キー値のみ取り出し/for in:値の取り出し)は使っていないようです。for in だと関数内で追加で定義宣言(これをよくプロトタイプ関数と言っています。)した関数が配列の中の要素として使われるので、値が関数でないかを確認しなくてはいけなくなったりします。複雑なプログラムでは実は意外と使いにくいfor in。for of で配列値を指定した場合はキーではなく、配列値が使えます。<syntaxhighlight lang="javascript" inline>for(var val 【of/in】 Array){…}</syntaxhighlight> | |||
以上の事を踏まえると、t.ready と t.preLoad と t.defaultReady と t.getRoot と t.checkVersion と t.pathFileters関数が作られて、これがどこから何回呼ばれるのかを確認することで、大部分を把握できて、if(void 0 === e.mathJax.loader) が成立したとき、つまり e.MathJax.loader が undefined のときに s.combineDefaults と s.combineWithMathJax に複雑な引数が渡される処理を実施して、最後に、 i(e.MathJax.config.loader.pathFilters) の結果得られる要素全てについての処理を行う処理が実施されるので、この動きを見極めればよいことになる。 | |||
==== t.ready ==== | |||
このメンバ関数はsampleのような単純なhtmlからだと呼ばれない関数になっていた。なので、内容をおいかけるのはあとあとです。 | |||
==== t.Load ==== | |||
5万1000行目付近の r.CONFIG.load で、このt.Load は呼ばれます。呼ばれた時の argument 値は | |||
{ | |||
"0": "input/tex-base", | |||
"1": "[tex]/newcommand", | |||
"2": "[tex]/action", | |||
"3": "output/chtml", | |||
} | |||
となっていました。argument を一旦、 o[0] ~ o[3] にコピーします。 | |||
そして、o の要素数が 0 なら、return Promise.resolve(); を返して終了ですが、そのようなことはないので、もう少し処理が進みます。l = []; で空の配列と c = function(r){…}で関数を定義します。o 要素の値を h に取り込んで for文で繰り返し処理します。先ほど定義した c(h) がすぐに使われます。関数 c の中で r は h で o の要素値です。その r をつかった n = a.Package.pacakages.get(r); で n は | |||
input/tex-base | |||
⇔ n= { name : input/tex-base, isLoaded : true, isLoading : false, hasFailed : false, | |||
noLoad : true, dependencyCount : 0, | |||
dependencies (1) | |||
0 : t { | |||
isLoaded: true, | |||
isLoading: false, | |||
hasFailed: false, | |||
dependencies: Array(1), | |||
dependents: Array(7), | |||
… | |||
} | |||
}, | |||
dependents : Array(7), | |||
canLoad : function() { /* noLoad true ⇒ return false */ | |||
return | |||
0 === this.dependencyCount && | |||
!this.noLoad && | |||
!this.isLoading && | |||
!this.hasFailed | |||
}, | |||
promise : Promise {[[PromiseState]]: 'pending', [[PromiseResult]]: undefined}, | |||
provided : [], | |||
reject : function(){}, | |||
resolve : function(){}, | |||
} | |||
[tex]/newcommand | |||
⇔ n = { name : [tex]/newcommand, isLoaded : true, isLoading : false, hasFailed : false, | |||
noLoad : true, dependencyCount : 0, | |||
… | |||
} | |||
[tex]/action | |||
⇔ n = { name : [tex]/action, isLoaded : true, isLoading : false, hasFailed : false, | |||
noLoad : true, dependencyCount : 0, | |||
… | |||
} | |||
output/chtml | |||
⇔ n = { name : output/chtml, isLoaded : true, isLoading : false, hasFailed : false, | |||
noLoad : true, dependencyCount : 0, | |||
… | |||
} | |||
} | |||
となります。 | |||
関数 c では、こうして作られた4つのa.Package.pacakages.nameについて l.push という操作で Promise がスタックされるところが重要な処理になってるみたい。Promise が 具体的に何なのかを明確に理解していないのでわからないですが、大事なポイントなので後で整理するとしよう。 | |||
そして、finally で さきほど使った next() による for 文のときにつかった 一時的に配列をスキャンしてカウントしていく p.done がちゃんと true になったか確認して !p.done が false ならちゃんと処理したものとしてエラーを出さずに最後の return 処理をします。 ここで出てくるのが a.Package.loadAll() ですが、このloadALLはMathJaxで作られた関数です。以下のような内容。 | |||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
function() { | function() { | ||
1,095行目: | 2,129行目: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
this.packages.values() は、 以下のような値になっていました。 | |||
[[Entries]] | |||
{ | |||
0 : {"loader" => t}, | |||
==== t | 1 : {"core" => t}, | ||
2 : {"startup" => t}, | |||
3 : {"input/tex" => t}, | |||
4 : {"input/tex-base" => t}, | |||
5 : {"[tex]/ams" => t}, | |||
6 : {"[tex]/newcommand" => t}, | |||
7 : {"[tex]/noundefined" => t}, | |||
8 : {"[tex]/require" => t}, | |||
9 : {"[tex]/autoload" => t}, | |||
10 : {"[tex]/configmacros" => t}, | |||
11 : {"input/mml" => t}, | |||
12 : {"output/chtml" => t}, | |||
13 : {"output/chtml/fonts/tex.js" => t}, | |||
14 : {"ui/menu" => t}, | |||
15 : {"a11y/assistive-mml" => t}, | |||
16 : {"[tex]/action" => t}, | |||
} | |||
this.packages.values() の 要素 を n とすると、 n.value.name として得られるのが上記の値です。 | |||
この値って何だろうって考えたとき、 最初の | |||
"0": "input/tex-base", | |||
"1": "[tex]/newcommand", | |||
"2": "[tex]/action", | |||
"3": "output/chtml", | |||
から増えているので、chtml形式の出力のときに使われる、ファイル群なのではないかと思いました。なのでそういうファイルがes5ディレクトリの中にあるか確認をしてみました。すると | |||
core.js ある! | |||
loader.js ある! | |||
startup.js ある! | |||
a11y/assistive-mml.js ある! | |||
input/mml.js ある! | |||
input/tex.js ある! | |||
input/tex-base.js ある! | |||
output/chtml.js ある! | |||
output/chtml/fonts/tex.js ある! | |||
ui/menu.js ある! | |||
で[tex]というのが input/tex/extensions ならば | |||
input/tex/extensions/action.js ある! | |||
input/tex/extensions/ams ある! | |||
input/tex/extensions/autoload ある! | |||
input/tex/extensions/configmacros ある! | |||
input/tex/extensions/newcommand ある! | |||
input/tex/extensions/noundefined ある! | |||
input/tex/extensions/require ある! | |||
という関係なので、ファイル名を差してるんだろうね。てことはこのクソ長い5万行のプログラムに加えて、17の外部ファイルが、読み込まれる可能性がありそう。ということなので、すべてのファイルを自動整形して、1行目にブレークポイントを設定しておく必要がありそう。1行目が呼ばれるかどうかはわかないのだけど、とりあえずってことです。 | |||
そして、o.canLoad は 以下のような関数で | |||
{ | |||
return | |||
0 === this.dependencyCount && | |||
!this.noLoad && | |||
!this.isLoading && | |||
!this.hasFailed | |||
} | |||
this.noLoad が true なので retrun は false になります。!this.noLoad ではじめて 0 になるので、この値が return の対象になります。先にも登場しましたが、念のため記述しておくと、[[JAVA Script 論理演算子と関数の代入式の併用]]に詳しい説明があります。 | |||
o.canLoad && o.load() | |||
も同じ理屈で o.canLoad までが処理対象になります。ちなみに o.load は以下のような関数です。 | |||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
function() { | |||
if(!this.isLoaded && !this.isLoading && !this.noLoad) { | |||
this.isLoading = !0; | |||
var e = t.resolvePath(this.name); | |||
l.CONFIG.require ? this.loadCustom(e) : this.loadScript(e) | |||
} | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
今回は処理されない部分なので、こちらとしても深追いしません。走ったとしても noLoad のところで false なので if文の中の命令は処理されません。 | |||
んで、やっぱり、ちゃんとfor文の処理がされたかをfinalyの処理で確かめてますね。これは定石のように何回も登場する例外処理です。 | |||
==== t.preLoad ==== | |||
r.Loader.preLoad("loader"), r.Loader.load.apply(r.Loader, function(t) {…} 後ろから探した方が早いくらいのとこにあるこの部分で実行されます。 | |||
最初のfor文の中で使われる argument 引数は、以下のようなものです。 | |||
{ | |||
"0": "loader", | |||
"1": "startup", | |||
"2": "core", | |||
"3": "input/tex", | |||
"4": "input/mml", | |||
"5": "output/chtml", | |||
"6": "output/chtml/fonts/tex.js", | |||
"7": "ui/menu", | |||
"8": "a11y/assistive-mml", | |||
} | |||
これはファイル群です。html 側で定義した Load ファイルは、'input/tex-base', '[tex]/newcommand', '[tex]/action', 'output/chtml'でしたが、それとは違う Load ファイルとなります。この 9 つの引数を n[o] の配列にコピー。この 9 つのファイル名について、for文で | |||
<syntaxhighlight lang="javascript" inline> | |||
u = a.Package.packages.get(c); | |||
</syntaxhighlight> | |||
a.Package.packages に結び付いた ファイル名の Key に対応する値を取得し u に格納します。 u に何も結び付いていなければ、次の行の処理をします。基本的には、最初の呼び出しでは何も結び付いていないので、次の処理をするのが目的だと思います。<syntaxhighlight lang="javascript" inline> u = new a.Package(c, !0) </syntaxhighlight> を実行すると <syntaxhighlight lang="javascript" inline>void 0 === r && (r = !1), this.isLoaded = !1, this.isLoading = !1, this.hasFailed = !1, this.dependents = [], this.dependencies = [], this.dependencyCount = 0, this.provided = [], this.name = e, this.noLoad = r, t.packages.set(e, this), this.promise = this.makePromise(this.makeDependencies())</syntaxhighlight> という設定がなされて、name が ファイル名で、t(⇔a.Packages).pakeages.set(ファイル名)で、それ以外のメンバ変数が各種設定がされたような a.Package.Packeges.get(ファイル名) が構築されます。 因みに promise は非同期処理の順序処理に関する定義をするものです。これらのファイルの処理に関する非同期を制御する予定があるんだなと思っとけばいいかな。その制御をする makePromise メンバ関数と makeDependencies メンバ関数があります。 | |||
makePromise関数はこんな感じ。 | |||
<syntaxhighlight lang="javascript"> | |||
function(t) { | |||
var e = this, | |||
r = new Promise( | |||
( | |||
function(t, r) { | |||
e.resolve = t, e.reject = r | |||
} | |||
) | |||
), | |||
n = l.CONFIG[this.name] || {}; | |||
return n.ready && | |||
( | |||
r = r.then( | |||
( | |||
function(t) { | |||
return n.ready(e.name) | |||
} | |||
) | |||
) | |||
), | |||
t.length && | |||
( | |||
t.push(r), | |||
r = Promise.all(t).then( | |||
( | |||
function(t) { | |||
return t.join(", ") | |||
} | |||
) | |||
) | |||
), | |||
n.failed && | |||
r.catch( | |||
( | |||
function(t) { | |||
return n.failed(new c(t, e.name)) | |||
} | |||
) | |||
), | |||
r /*カンマ演算子の最右値 return 対象*/ | |||
} | |||
</syntaxhighlight> | |||
引数の最初 t は 次の処理を指定していて、第二引数が非同期処理が失敗した時の値のようですね。全部の処理が終わった時も t が次の処理になるようになっているように見えます。全部の処理が終わったかをみる場合の t は文字列っぽいですね。全部の名前文字列を , 区切りで結合して保持する処理があったりしています。l.CONFIG[ファイル名]の .ready というメンバ変数に呼び出し元オブジェクトで関数を入れておけば、それが、このPromiseを宣言した時点で実行されそうにも見えます。r は Promise の 結果であるオブジェクトが持たれていて、 PromiseStatus : Pending or Resolved or Rejected と PromiseResult undefined or 成功時の関数・変数 t のもしくは 失敗時の変数 r の呼び出しが保持されます。非同期処理中の成功・失敗はデバッグ処理でもたついたときにも発生するので、あまり長いことブレークしすぎないような工夫をしながら、デバッグする必要もありそうです。見る時は一か所でじっくり見て、次に進むときは再起動して次のポイントを見るとかね。 | |||
最初の呼び出しはファイル名 r = [tex]/action でした。 | |||
<syntaxhighlight lang="javascript" inline> | |||
(n = new a.Package(r)).provides(e.CONFIG.provides[r]) | |||
</syntaxhighlight> | |||
Packageを定義しましたが、.provides では e.CONFIG.provides[r] が undefined なので、特に何もしませんでした。ふむ。 | |||
次にn.CheckNoLoad()が実行されます。以下のような関数です。 | |||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
function() { | |||
var | var t, e; | ||
this. | if(this.noLoad) { | ||
this.noLoad = !1; | |||
try { | |||
for(var r = i(this.dependencies), n = r.next(); !n.done; n = r.next()) { | |||
n.value.checkNoLoad() | |||
} | |||
} catch(e) { | |||
t = { | |||
error: e | |||
} | |||
} finally { | |||
try { | |||
n && !n.done && (e = r.return) && e.call(r) | |||
} finally { | |||
if(t) throw t.error | |||
} | |||
} | |||
} | } | ||
} | } | ||
1,308行目: | 2,328行目: | ||
NoLoad は最初 true でしたが、反転します。そして、最初のファイル名についてのi(this.dependencies)の結果についても個別にCheckNoLoadを再帰して呼び出します。 | |||
i は下に示すような関数で ファイル名のオブジェクト this.dependencies {0: {isLoaded: true, isLoading: false, hasFailed: false, dependents: Array(7), dependencies: Array(1), …} } はこんな感じです。ずっとループする this.dependencies[0].dependencies[0].… とループする構造です。 | |||
<syntaxhighlight lang="javascript"> | |||
function(t) { | |||
var e = "function" == typeof Symbol && Symbol.iterator, | |||
r = e && t[e], | |||
n = 0; | |||
if(r) return r.call(t); | |||
if(t && "number" == typeof t.length) return { | |||
next: function() { | |||
return t && n >= t.length && (t = void 0), { | |||
value: t && t[n++], | |||
done: !t | |||
} | |||
} | |||
}; | |||
throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.") | |||
} | |||
</syntaxhighlight> | |||
"function" == typeof Symbol は true なので、e = Symbol.iterator で、 r = e と同じ結果により if(r)が true で r.call(t) が return 対象で、{isLoaded: true, isLoading: false, hasFailed: false, dependents: Array(7), dependencies: Array(1), …} が 返却されます。noLoad はないので n.valuse.CheckNoLoad() は 最初のif文でfalseなので、なにも帰さないです。再帰から脱出です。 | |||
そして l.push(n.Promise.then(…)) によって非同期処理の完了後処理がスタックされていきます。 | |||
<syntaxhighlight lang="javascript" inline>o = ['input/tex-base', '[tex]/newcommand', '[tex]/action', 'output/chtml'] </syntaxhighlight>で、繰り返して処理をします。 | |||
最後に<syntaxhighlight lang="javascript" inline>return a.Package.loadAll(), Promise.all(l)</syntaxhighlight>で | |||
LoadAll()は以下のような関数を実行します。 | |||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
function | function() { | ||
var | var t, e; | ||
try { | try { | ||
for(var | for(var r = i(this.packages.values()), n = r.next(); !n.done; n = r.next()) { | ||
var | var o = n.value; | ||
o.canLoad && o.load() | |||
} | } | ||
} catch( | } catch(e) { | ||
t = { | |||
error: | error: e | ||
} | } | ||
} finally { | } finally { | ||
try { | try { | ||
n && !n.done && (e = r.return) && e.call(r) | |||
} finally { | } finally { | ||
if( | if(t) throw t.error | ||
} | } | ||
} | } | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
各ファイル名のオブジェクトについて、o.canload が true なら load() を実行していく感じですね。ファイルをロードするのにものすごく非同期処理の順序を気にしている感じがします。確実に全部読み込んでから実行するためなのでしょう。エラーは絶対に出さないという強い意志を感じる凄みがあります。 | |||
==== t.defaultReady ==== | |||
<syntaxhighlight lang="javascript" inline>void 0 !== e.MathJax.startup && e.MathJax.config.startup.ready()</syntaxhighlight> の一行の処理で、e.MathJax.startup は定義されていれば、void 0 !== e.MathJax.startup が true で、定義されていたら、e.MathJax.config.startup.ready() を実行するというのが全て。呼ばれるのは、最後から4行目あたりのreturn r.CONFIG.ready()で呼ばれる。 | |||
===== e.MathJax.config.startup.ready() ===== | |||
e.MathJax.config.startup.ready() は、以下のような関数。 | |||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
t. | { | ||
f(), | |||
d(), | |||
t.pagePromise.then( | |||
( | |||
function() { | |||
return e.CONFIG.pageReady() | |||
} | |||
) | |||
).then( | |||
( | ( | ||
function() { | |||
return t.promiseResolve() | |||
} | |||
) | ) | ||
).catch( | |||
( | ( | ||
function(e) { | |||
return t.promiseReject(e) | |||
} | |||
) | ) | ||
) | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
===== e.MathJax.config.startup.ready() { f() }===== | |||
f() は、 | |||
<syntaxhighlight lang="javascript"> | |||
a = new e.MathJax._.core.MmlTree.SerializedMmlVisitor.SerializedMmlVisitor, | |||
l = e.MathJax._.mathjax.mathjax, | |||
t.input = v(), | |||
t.output = _(), | |||
t.adaptor = S(), | |||
t.handler && l.handlers.unregister(t.handler), | |||
t.handler = M(), | |||
t.handler && (l.handlers.register(t.handler), | |||
t.document = O()) | |||
</syntaxhighlight> | |||
一行だからってなめてたけど、めっちゃ処理されるじゃん。深い!a = { NodeHandlers : Map(5){size: 5, inferredMrow => ƒ (t, e), annotation => ƒ (t, e), TeXAtom => ƒ (t, e), text => ƒ (t, e), XML => ƒ (t, e)} | |||
e.MathJax._.core.MmlTree.SerializedMmlVisitor.SerializedMmlVisitor は、こんな関数 | |||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
e.MathJax._.core.MmlTree.SerializedMmlVisitor.SerializedMmlVisitor = function r() { | |||
return null !== t && t.apply(this, arguments) || this | |||
} | |||
</syntaxhighlight> | |||
この時の t は | |||
<syntaxhighlight lang="javascript"> | |||
t = function e(e){ | |||
return | |||
void 0 === e && (e = null), | |||
e || (e = new i.MmlFactory), | |||
t.call(this, e) || this | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
で、e は undefined で、返却される値は t.call(this, e) || this で、e が いったん null値になった後、<syntaxhighlight lang="javascript" inline>e = new i.MmlFactory</syntaxhighlight> で <syntaxhighlight lang="javascript" inline> function e() { return null !== t && t.apply(this, arguments) || this }</syntaxhighlight> がその内容になっています。 | |||
e { | |||
defaultKind: 'unknown', | |||
nodeMap: Map(42) {size: 42, | |||
math => function e() { | |||
return null !== t && t.apply(this, arguments) || this | |||
} | |||
mi => ƒ e(), | |||
mn => ƒ e(), | |||
mo => ƒ e(), | |||
mtext => ƒ e(), | |||
mspace | |||
ms => ƒ e(), | |||
mrow => ƒ e(), | |||
inferredMrow => ƒ e(), | |||
mfrac => ƒ e(), | |||
msqrt => ƒ e(), | |||
mroot => ƒ e(), | |||
mstyle => ƒ e(), | |||
merror => ƒ e(), | |||
mpadded => ƒ e(), | |||
mphantom => ƒ e(), | |||
mfenced => ƒ e(), | |||
menclose => ƒ e(), | |||
maction => ƒ e(), | |||
msub => ƒ e(), | |||
msup => ƒ e(), | |||
musubsup => ƒ e(), | |||
munder => ƒ e(), | |||
mover => ƒ e(), | |||
munderover => ƒ e(), | |||
mmultiscripts => ƒ e(), | |||
mprescript => ƒ e(), | |||
none => ƒ e(), | |||
mtable => ƒ e(), | |||
mlabeledtr => ƒ e(), | |||
mtr => ƒ e(), | |||
mtd => ƒ e(), | |||
maligngtoup => ƒ e(), | |||
malignmark => ƒ e(), | |||
mglyph => ƒ e(), | |||
semantics => ƒ e(), | |||
annotation => ƒ e(), | |||
annotation-xml => ƒ e(), | |||
TexAtom => ƒ e(), | |||
MathChoice => ƒ e(), | |||
text => ƒ e(), | |||
XML => ƒ e(), | |||
} | |||
node: { | |||
annotation : ƒ { | |||
for(var t = [], e = 0; e < arguments.length; e++) | |||
t[e] = arguments[e]; | |||
return new( | |||
i.bind.apply( | |||
i, | |||
o( | |||
[void 0, r], | |||
n(t), | |||
!1 | |||
) | |||
) | |||
) | |||
}, | |||
annotation-xml : ƒ, | |||
inferredMrow : ƒ, | |||
maction : ƒ, | |||
maligngroup : ƒ, | |||
malignmark : ƒ, | |||
math : ƒ, | |||
MathChoice : ƒ, | |||
menclose : ƒ, | |||
merror : ƒ, | |||
mfenced : ƒ, | |||
mfrac : ƒ, | |||
mglyph : ƒ, | |||
} | mi : ƒ, | ||
} | mlabeledtr : ƒ, | ||
mmultiscripts : ƒ, | |||
mn : ƒ, | |||
mo : ƒ, | |||
mover : ƒ, | |||
mpadded : ƒ, | |||
mphantom : ƒ, | |||
mprescripts : ƒ, | |||
mroot : ƒ, | |||
mrow : ƒ, | |||
ms : ƒ, | |||
mspace : ƒ, | |||
msqrt : ƒ, | |||
mstyle : ƒ, | |||
msub : ƒ, | |||
msubsup : ƒ, | |||
msup : ƒ, | |||
mtable : ƒ, | |||
mtd : ƒ, | |||
mtext : ƒ, | |||
mtr : ƒ, | |||
munder : ƒ, | |||
munderover : ƒ, | |||
mnone : ƒ, | |||
semantics : ƒ, | |||
TeXAtom : ƒ, | |||
text : ƒ, | |||
XLM : ƒ, | |||
math: ƒ, mi: ƒ, mn: ƒ, mo: ƒ, mtext: ƒ, …} | |||
} | |||
となってから、t.call(this, e) || this が 呼び出される。 | |||
t は、以下のような関数です。 | |||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
ƒ t(e) { | |||
var | var r, o; | ||
this.nodeHandlers = new Map; | |||
try { | try { | ||
for(var i = n(e.getKinds()), s = i.next(); !s.done; s = i.next()) { | |||
var a = s.value, | |||
l = this[t.methodName(a)]; | |||
l && this.nodeHandlers.set(a, l) | |||
} | |||
} catch(t) { | } catch(t) { | ||
r = { | |||
error: t | |||
} | |||
} finally { | } finally { | ||
try { | |||
s && !s.done && (o = i.return) && o.call(i) | |||
} finally { | |||
if(r) throw r.error | |||
} | |||
} | } | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
s.value は Mathから始まる値で a に代入される。<syntaxhighlight lang="javascript" inline>"visit" + (t.charAt(0).toUpperCase() + t.substr(1)).replace(/[^a-z0-9_]/gi, "_") + "Node" </syntaxhighlight> が返されて、t.methodName(a) は visitMathNodeが返ってくる。そのような名前の配列がthisに無いので undefined になることが多い。Mathの部分が一文字が大文字になったものと残りの文字をくっつける。その結果でも先頭文字が数字だったり小文字だったり_だったりしたら_に置き換える。という処理をする。ふむ。this.nodeHandlers.set で元の a の値と 変換された結果得られる this.['visitXxxxxNode'] が undefined だろうと 何かあったろうと ついにして set に設定する。残りの命令は例によって、for文が最後まで処理できたかを確認している。そうやってできたオブジェクト t を返却として準備する。 | |||
そして、l = {version: '3.2.2', handlers: e, document: <syntaxhighlight lang="javascript" inline>ƒ (t, r) {return e.mathjax.handlers.document(t, r)}</syntaxhighlight>, handleRetriesFor: <syntaxhighlight lang="javascript" inline>ƒ (t) {return new Promise((function e(r, n) {try {r(t())} catch(t) {t.retry && t.retry instanceof Promise ? t.retry.then((function() {return e(r, n)})).catch((function(t) {return n(t)})) : t.restart && t.restart.isCallback ? MathJax.Callback.After((function() {return e(r, n)}), t.restart) : n(t)}}))}</syntaxhighlight>, retryAfter: <syntaxhighlight lang="javascript" inline>ƒ (t) {var e = new Error("MathJax retry");throw e.retry = t, }</syntaxhighlight>, asyncLoad :<syntaxhighlight lang="javascript" inline>ƒ (t) {return MathJax.loader.load(t)}</syntaxhighlight>, handlers : { item: [] }} 次に t.input の関数 v()は…とその前に… | |||
まだf() の最初の2行しか追えてない。残り7行あるし、d()も、その次も残ってる。ナゲー。preLoad やばい。 | |||
t.input = v(), | |||
t.output = _(), | |||
t.adaptor = S(), | |||
t.handler && l.handlers.unregister(t.handler), | |||
t.handler = M(), | |||
t.handler && (l.handlers.register(t.handler), | |||
t.document = O()) | |||
困ったね。 | |||
==== | ===== e.MathJax.config.startup.ready() { v() }===== | ||
それで v()なんだけども | |||
<syntaxhighlight lang="javascript"> | |||
function v() { | |||
var r, n, i = []; | |||
try { | |||
for(var s = o(e.CONFIG.input), a = s.next(); !a.done; a = s.next()) { | |||
var l = a.value, | |||
c = t.constructors[l]; | |||
if(!c) throw Error('Input Jax "' + l + '" is not defined (has it been loaded?)'); | |||
i.push(new c(e.MathJax.config[l])) | |||
} | |||
} catch(t) { | |||
r = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
a && !a.done && (n = s.return) && n.call(s) | |||
} finally { | |||
if(r) throw r.error | |||
} | |||
} | |||
return i | |||
} | |||
</syntaxhighlight> | |||
e.CONFIG.input = ['tex', 'mml'] で o() は iterator を返す関数(繰り返し処理する要素をまとめるもの)なので、結局次のように処理されます。 i.push(new c(e.MathJax.config['tex'])) → i.push(new c(e.MathJax.config['mml'])) このようにして呼ばれる c は、以下のような関数です。i.push(new c(e.MathJax.config['mml'])) は html側で定義していないので何も情報がないので、大した処理はされないはずです。 | |||
===== e.MathJax.config.startup.ready() { f() > c }===== | |||
<syntaxhighlight lang="javascript"> | |||
c = function(r) { | |||
void 0 === r && (r = {}); | |||
var n = this, | |||
o = s( | |||
( | |||
0, | |||
c.separateOptions | |||
) | |||
( | |||
r, | |||
e.OPTIONS, | |||
u.FindTeX.OPTIONS | |||
), | |||
3 | |||
), | |||
i = o[0], | |||
a = o[1], | |||
l = o[2]; | |||
( | |||
n = t.call(this, a) || | |||
this | |||
).findTeX = n.options.FindTeX || | |||
new u.FindTeX(l); | |||
var h = n.options.packages, | |||
f = n.configuration = e.configure(h), | |||
d = n._parseOptions = new m.default(f, [n.options, y.TagsFactory.OPTIONS]); | |||
return | |||
( | |||
0, | |||
c.userOptions | |||
) | |||
( | |||
d.options, | |||
i | |||
), | |||
f.config(n), | |||
e.tags(d, f), | |||
n.postFilters.add(p.default.cleanSubSup, -6), | |||
n.postFilters.add(p.default.setInherited, -5), | |||
n.postFilters.add(p.default.moveLimits, -4), | |||
n.postFilters.add(p.default.cleanStretchy, -3), | |||
n.postFilters.add(p.default.cleanAttributes, -2), | |||
n.postFilters.add(p.default.combineRelations, -1), | |||
} | |||
</syntaxhighlight> | |||
なげー。プログラムだらけだな。これを c として、引数に e.MathJax.config[l] を迎え、 i.push(new c(e.MathJax.config['tex'])) → i.push(new c(e.MathJax.config['mml']))のように順番に i にプッシュされてスタックを作る。e.MathJax.config['tex']には inline のキーワード が格納されている。よく使われるのは $$ , $$とか \( , \) とかですね。inlineMath packages とか身近なキーワードうれしい。この命令は html で 設定した config の tex や mml を取得する部分なんだろうなって思う。だけど上のプログラムの引数 r がそうなんだけど inline とか packages がまだないね。淋しい。あー packages あるわ。n.option.packages ね。ってことは 今回は mml は定義してないから何もしない感じだな。 | |||
これが u.FindTeX.OPTIONS の値。 デフォルトの tex の option 値 っぽいのが設定されている。おー知ってるのまた出てきた。 | |||
<syntaxhighlight lang="javascript"> | |||
{ | |||
inlineMath: [ | |||
["\\(", "\\)",], | |||
], | |||
displayMath: [ | |||
["$$", "$$", ], | |||
["\\[", "\\]",], | |||
], | |||
processEscapes: true, | |||
processEnvironments: true, | |||
processRefs: true, | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
===== e.MathJax.config.startup.ready() { f() > c > separateOptions}===== | |||
以下が、c.separateOptions関数。 | |||
<syntaxhighlight lang="javascript"> | |||
c.separateOptions = function(t) { | |||
for(var e, n, o, i, s = [], a = 1; a < arguments.length; a++) | |||
s[a - 1] = arguments[a]; | |||
var l = []; | |||
try { | |||
for(var c = r(s), u = c.next(); !u.done; u = c.next()) { | |||
var p = u.value, | |||
h = {}, | |||
f = {}; | |||
try { | |||
for(var d = (o = void 0, r(Object.keys(t || {}))), m = d.next(); !m.done; m = d.next()) { | |||
var y = m.value; | |||
(void 0 === p[y] ? f : h)[y] = t[y] | |||
} | |||
} catch(t) { | |||
o = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
m && !m.done && (i = d.return) && i.call(d) | |||
} finally { | |||
if(o) throw o.error | |||
} | |||
} | |||
l.push(h), t = f | |||
} | |||
} catch(t) { | |||
e = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
u && !u.done && (n = c.return) && n.call(c) | |||
} finally { | |||
if(e) throw e.error | |||
} | |||
} | |||
return l.unshift(t), l | |||
} | |||
</syntaxhighlight> | |||
あーなるほど。なるほど、動かしてみると引数が3つあった意味が分かった。全部使われるんだね。関数名の横の引数名をあたえるところが一つしかなくても、変数に格納されないだけで argument という特別な変数には、全部の引数が配列に格納されてました。こういう方法もあるんだな。t はユーザが設定した引数。 s[0] に第二引数、s[1] に第三引数が格納される感じで使う。なぜこうやってねじるようなことをするのかはわからない。 | |||
u.value はすでに、こういった設定情報をすでに保持している変数で、p にそのまま格納しているが、その結果、p の中身は以下のようになっています。 | |||
{ | |||
FindTeX: null, | |||
packages: ["base",], | |||
digits: {}, | |||
maxBuffer: 5120, | |||
formatError: function(t, e) { return t.formatError(e) }, | |||
} | |||
という具合で packages メンバはあるが inlineMath は無い状態。 | |||
Object.keys(t || {}) = ['inlineMath', 'packages'] はユーザが指定したオプションです。このkeyと u の値のキーと一致するものがあるかないかを2項演算子で比較して あれば ? の後ろの f[y] = t[y] なければ h[y] = t[y] となります。h[y] には一致しない属性が集まります。f[y] には一致した属性があつまります。 全てを処理したら、l.push(h) で新しい属性を lにプッシュします。, 重複したキーの値は t = f で t に格納します。 最後に関数はスタックした l から t を 取り除いて、l を 返却します。 | |||
したがって、最初の2項演算子「 A ? true_instruction : false_instruction」は false で、h[y] = t[y] になります。h も f も最初は空の配列なので、h[y] が tex のときの値、 f[y] が packages のときの値になります。 | |||
h[y] = { | |||
inlineMath: [ [ "$", "$", ], ["\\(", "\\)",],], | |||
} | |||
f[y] = { | |||
packages: [ "base", "newcommand", "action", ], | |||
} | |||
となります。この後 l.push(h) で h の inlineMath の設定情報が l に保持されます。t にも f の内容がコピーされます。そして、全ての繰り返し処理をした後 <syntaxhighlight lang="javascript" inline>return l.unshift(t), l</syntaxhighlight>でlの配列の先頭にtが挿入されますが、2回目の処理のときに t は {} になっています。そして2回目で packages が l に追加でスタックされます。ので、[{ … },{packages : ['base', 'newcommand', 'action']}, {inlineMath :{ … : [ … ]} }, ]という状態になります。 | |||
===== e.MathJax.config.startup.ready() { f() > c > s()}===== | |||
その後、関数が呼ばれる s は以下のようなモノ。 | |||
<syntaxhighlight lang="javascript"> | |||
s = function(t, e) { | |||
var r = "function" == typeof Symbol && t[Symbol.iterator]; | |||
if(!r) return t; | |||
var n, o, i = r.call(t), | |||
s = []; | |||
try { | |||
for(; | |||
(void 0 === e || e-- > 0) && !(n = i.next()).done;) s.push(n.value) | |||
} catch(t) { | |||
o = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
n && !n.done && (r = i.return) && r.call(i) | |||
} finally { | |||
if(o) throw o.error | |||
} | |||
} | |||
return s | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
s の呼び出しの第一引数が複雑な表記になっている。第二は 3 だけ。短っ。 でも引数は[{ … },{packages : ['base', 'newcommand', 'action']}, {inlineMath :{ … : [ … ]} }, ]です。 r は 値がある状態なので、!r 非成立。次に進みます。そして、第一引数のそのものである i で繰り返し処理をすると s に[{ … },{packages : ['base', 'newcommand', 'action']}, {inlineMath :{ … : [ … ]} }, ]がコピーされる感じになります。戻り値でもあるので、だいぶん前の c の関数の中の o にもコピーされます。この処理を全体的にみると s の配列の1番目は空{} 2番目は inlineMath 以外の値、 3番目は packages 以外の値が格納されます。 | |||
第一引数の手前のカッコの一番右がカンマ構文では有効な値で、 c.separateOptions は関数で、その後ろのカッコが引数になっていると思われる。ここでもまたカンマ構文があるがここは引数なので、カンマ左の一つ目が採用される。なので自分で設定した r が使われる。 r が設定されていなかったら2つめ、3つめが使われるんだっけか。この表記の意味がわかんねぇ。調べよっか。 | |||
i = 空{}、a = inlineMath 以外の値、l = packages 以外の値が格納されます。t.call(this, a)では、aはHTMLで指定したpackages : ['base', 'newcommand', 'action'] です。t はこんな関数。 | |||
<syntaxhighlight lang="javascript"> | |||
function t(t) { | |||
void 0 === t && (t = {}), this.adaptor = null, this.mmlFactory = null; | |||
var e = this.constructor; | |||
this.options = (0, n.userOptions)((0, n.defaultOptions)({}, e.OPTIONS), t), | |||
this.preFilters = new o.FunctionList, | |||
this.postFilters = new o.FunctionList | |||
} | |||
</syntaxhighlight> | |||
最初の2行ではthisがundefinedなので、何もせず、メンバ変数が作られるだけです。3行目は 関数の引数に関数が使われている感じで n.userOptions( (n.defaultOptions({}, e.Options)), t) ですから n.defaultOptions({}, e.Options)が算出されます。引数の e.Options は 以下の値 です。 | |||
{ | |||
FindTeX: null, | |||
packages: Array(1), | |||
digits: /^(?:[0-9]+(?:\\{,\\}[0-9]{3})*(?:\\.[0-9]*)?|\\.[0-9]+)/, | |||
maxBuffer: 5120, | |||
formatError: ƒ | |||
} | |||
<syntaxhighlight lang="javascript"> | |||
n.defaultOptions = function(t) { | |||
for(var e = [], r = 1; r < arguments.length; r++) | |||
e[r - 1] = arguments[r]; | |||
return e.forEach( | |||
( | |||
function(e) { | |||
return p(t, e, !1) | |||
} | |||
) | |||
), t | |||
} | |||
</syntaxhighlight> | |||
このときの e.Options = t は | |||
{ | |||
parseAs : 'html', | |||
forceReparse : false, | |||
FindMathML : null, | |||
MathMLCompile : null, | |||
} | |||
というような値です。 | |||
ここでも関数名の横の引数が t だけと少なく arguments で全ての引数を処理しています。引数を e で格納して、return で t を返却します。 t を返却する前に p に {}, e (=e.OPTIONS), false という引数を渡した処理をします。 | |||
p は以下のような関数です。 | |||
<syntaxhighlight lang="javascript"> | |||
function p(t, i, l) { | |||
var h, f; | |||
void 0 === l && (l = !0); | |||
/* Define d Function */ | |||
var d = function(r) { | |||
if(l && void 0 === t[r] && t.constructor !== a) | |||
return "symbol" == typeof r && | |||
(r = r.toString()), e.OPTIONS.optionError('Invalid option "'.concat(r, '" (no default value).'), r), | |||
"continue"; | |||
var h = i[r], | |||
f = t[r]; | |||
if(!s(h) || null === f || "object" != typeof f && "function" != typeof f) | |||
Array.isArray(h) ? (t[r] = [], p(t[r], h, !1)) : s(h) ? t[r] = u(h) : t[r] = h; | |||
else { | |||
var d = c(h); | |||
Array.isArray(f) && | |||
( | |||
1 === d.length && | |||
(d[0] === e.APPEND || d[0] === e.REMOVE) && | |||
Array.isArray(h[d[0]]) || 2 === d.length && | |||
d.sort().join(",") === e.APPEND + "," + e.REMOVE && | |||
Array.isArray(h[e.APPEND]) && | |||
Array.isArray(h[e.REMOVE]) | |||
)? | |||
(h[e.REMOVE] && | |||
(f = t[r] = f.filter | |||
((function(t) { | |||
return h[e.REMOVE].indexOf(t) < 0 | |||
}) | |||
) | |||
), | |||
h[e.APPEND] && (t[r] = o(o([], n(f), !1), | |||
n(h[e.APPEND]), !1))) | |||
: | |||
p(f, h, l) | |||
} | |||
}; | |||
/* Define d Function End*/ | |||
try { | |||
for(var m = r(c(i)), y = m.next(); !y.done; y = m.next()) { | |||
d(y.value) | |||
} | |||
} catch(t) { | |||
h = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
y && !y.done && (f = m.return) && f.call(m) | |||
} finally { | |||
if(h) throw h.error | |||
} | |||
} | |||
return t | |||
} | |||
</syntaxhighlight> | |||
この関数を実行したあとのe.forEachの関数の引数には | |||
0 : { | |||
unknownFamily: "serif", | |||
fontURL: "js/output/chtml/fonts/tex-woff-v2", | |||
}, | |||
1 : { | |||
unknownFamily: "serif", | |||
fontURL: "js/output/chtml/fonts/tex-woff-v2", | |||
} | |||
となります。そして t を返す。 | |||
<syntaxhighlight lang="javascript"> | |||
c = function(t){ | |||
return t ? Object.keys(t).concat(Object.getOwnPropertySymbols(t)) : [] | |||
} | |||
</syntaxhighlight> | |||
で pacakges : ['base', 'newcommand', 'action'] の配列が返却。 | |||
<syntaxhighlight lang="javascript"> | |||
r = function() { | |||
var e = "function" == typeof Symbol && Symbol.iterator, | |||
r = e && t[e], | |||
n = 0; | |||
if(r) return r.call(t); | |||
if(t && "number" == typeof t.length) return { | |||
next: function() { | |||
return t && n >= t.length && (t = void 0), { | |||
value: t && t[n++], | |||
done: !t | |||
} | |||
} | |||
}; | |||
throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.") | |||
} | |||
</syntaxhighlight> | |||
上記関数で r は空の関数で それに t = pacakges : ['base', 'newcommand', 'action'] を引数にしても以下のような値です。 | |||
{ | |||
value: pacakges, | |||
done: true, | |||
} | |||
t は ['base','newcomamand', 'action']です。 | |||
下記のようなところからpreLoadは呼ばれているようです。 | |||
r.Loader.preLoad( | |||
"input/tex-base", | |||
"[tex]/ams", | |||
"[tex]/newcommand", | |||
"[tex]/noundefined", | |||
"[tex]/require", | |||
"[tex]/autoload", | |||
"[tex]/configmacros"), | |||
function() { | |||
var t = arguments.length > 0 && | |||
void 0 !== arguments[0] ? arguments[0] : [], | |||
e = !(arguments.length > 1 && | |||
void 0 !== arguments[1]) || arguments[1]; | |||
if(MathJax.startup) { | |||
e && | |||
(MathJax.startup.registerConstructor("tex", MathJax._.input.tex_ts.TeX), | |||
MathJax.startup.useInput("tex") | |||
), | |||
MathJax.config.tex || | |||
(MathJax.config.tex = {}); | |||
var r = MathJax.config.tex.packages; | |||
MathJax.config.tex.packages = t, r && | |||
(0, xt.insert)(MathJax.config.tex, { | |||
packages: r | |||
}) | |||
} | |||
} (["base", "ams", "newcommand", "noundefined", "require", "autoload", "configmacros"]); | |||
<syntaxhighlight lang="javascript"> | |||
e.userOptions = function(t) { | |||
for(var e = [], r = 1; r < arguments.length; r++) | |||
e[r - 1] = arguments[r]; | |||
return e.forEach( | |||
(function(e) { | |||
return p(t, e, !0) | |||
}) | |||
), t | |||
} | |||
</syntaxhighlight> | |||
===== e.MathJax.config.startup.ready() { f() > c > defaltOption() > p()}===== | |||
<syntaxhighlight lang="javascript"> | |||
function p(t, i, l) { | |||
var h, f; | |||
void 0 === l && (l = !0); | |||
/* define function */ | |||
var d = function(r) { | |||
if(l && void 0 === t[r] && t.constructor !== a) { | |||
return "symbol" == typeof r && (r = r.toString()), | |||
e.OPTIONS.optionError('Invalid option "'.concat(r, '" (no default value).'), r), | |||
"continue"; | |||
} | |||
var h = i[r], | |||
f = t[r]; | |||
if(!s(h) || null === f || "object" != typeof f && "function" != typeof f) { | |||
Array.isArray(h) ? | |||
(t[r] = [], p(t[r], h, !1)) | |||
: | |||
s(h) ? | |||
t[r] = u(h) | |||
: | |||
t[r] = h; | |||
} | |||
else { | |||
var d = c(h); | |||
Array.isArray(f) && | |||
(1 === d.length && (d[0] === e.APPEND || d[0] === e.REMOVE) && | |||
Array.isArray(h[d[0]]) || | |||
2 === d.length && | |||
d.sort().join(",") === | |||
e.APPEND + "," + e.REMOVE && Array.isArray(h[e.APPEND]) && | |||
Array.isArray(h[e.REMOVE])) ? | |||
(h[e.REMOVE] && | |||
(f = t[r] = f.filter((function(t) { | |||
return h[e.REMOVE].indexOf(t) < 0 | |||
}))), h[e.APPEND] && (t[r] = o(o([], n(f), !1), n(h[e.APPEND]), !1))) : p(f, h, l) | |||
} | |||
}; | |||
/* define function end */ | |||
try { | |||
for(var m = r(c(i)), y = m.next(); !y.done; y = m.next()) { | |||
d(y.value) | |||
} | |||
} catch(t) { | |||
h = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
y && !y.done && (f = m.return) && f.call(m) | |||
} finally { | |||
if(h) throw h.error | |||
} | |||
} | |||
return t | |||
} | |||
</syntaxhighlight> | |||
この関数を実行すると l は true になります。そして関数を定義だけして try まで飛びます。中身はあとで読むことになるでしょう。後ですぐ呼ばれます。 | |||
r(c(i))で得られる繰り返し要素について処理します。最初は {value: 'FindTeX', done: false} です。次が {value: 'packages', done: false} … という具合です。そうして d(y.value)のようにして、d('FindTeX') → d('packages') → d('digits') → d('maxBuffer') → d('formatError') → という処理が呼ばれます。こうした処理の末に出来上がる t が返却される予定です。 d() の内容を確認します。 | |||
void 0 === t[r] が true になりますので 、t[r] は undefined が返される値です。最初の段階で t が {} なので t['FindeTex'] もないので、undefined になるのでしょう。そして、t.constructer は空のオブジェクトで a が空の関数で不一致するので、trueになります。結果全てが true の if の成立処理が実行されます。"symbol" == typeof r の r は 'FindTex' で "string" ですから、false です。 symbol以外のような文字列ならば、文字列に変換して r へ格納する処理は行われません。 | |||
e.OPTIONS.optionError('Invalid option "'.concat(r, '" (no default value).'), r)のような設定をしたら、この if 文は "continue" という文字列を返却します。h には i[r] で FindTeX に対応する null を返却します。t[t]はないので、f は undefinedになります。!s(h) の h は null ですが、 s(null) が falseで 反転してtrueになります。if文はこれで成立して、Array.isArray(h) が動作し、2項演算子は非成立を繰り返します。 | |||
次は、packages で [base, newcommand, action] という値が処理されます。 | |||
this.Option は | |||
{ | |||
FindTeX: null, | |||
packages: [ | |||
"base", | |||
"newcommand", | |||
"action", | |||
], | |||
digits: { /^(?:[0-9]+(?:\\{,\\}[0-9]{3})*(?:\\.[0-9]*)?|\\.[0-9]+)/ }, | |||
maxBuffer: 5120, | |||
formatError: function(t, e) { | |||
return t.formatError(e) | |||
}, | |||
} | |||
となります。 | |||
他にも | |||
this.preFilters = { items: [],} | |||
this.postFilters = { items: [],} | |||
という値も設定されます。 | |||
nは以下のような値になっています。 | |||
e { | |||
options: { inlineMath: 0: ['$', '$'], | |||
1: ['\(', '\)'] | |||
displayMath: 0: ['$$', '$$'], | |||
1: ['\[', '\]'], | |||
processEscapes: true, processEnvironments: true, processRefs: true}, | |||
end: { $:(3) ['$' , false, /\$|\\(?:[a-zA-Z]|.)|[{}]/g], | |||
\(:(3) ['\)', false, /\\\)|\\(?:[a-zA-Z]|.)|[{}]/g], | |||
$$:(3) ['$$', true, /\\$\$|\\(?:[a-zA-Z]|.)|[{}]/g], | |||
\[:(3) ['\]', true, /\\\]|\\(?:[a-zA-Z]|.)|[{}]/g] | |||
}, | |||
sub: 2, | |||
env: 1, | |||
start: /\$\$|\\\(|\\\[|\$|\\begin\s*\{([^}]*)\}|(\\([\\$])|(\\(?:eq)?ref\s*\{[^}]*\}))/g, … | |||
} | |||
h = ['base', 'newcommand', 'action']、 | |||
f = t { | |||
initMethod: e {関数}, | |||
configMethod : e { item : []} | |||
configratons : t { item : [0 : item t(関数), priority: 5], | |||
[1 : item t(関数), priority: 5], | |||
[2 : item t(関数), priority: 5], | |||
}, | |||
parsers: ["tex",], | |||
handlers: t map[{"character" => t}, | |||
items: {beginEnv: ƒ, start: ƒ, stop: ƒ, open: ƒ, close: ƒ, array: ƒ, call: ƒ, dot: ƒ, end: ƒ, eqnarray: ƒ, equation: ƒ, fn: ƒ, left: ƒ, middle: ƒ, mml: ƒ, noscript: ƒ, not: ƒ, position: ƒ, prime: ƒ, right: ƒ, style: ƒ, subsup: ƒ, }, | |||
nodes: {}, | |||
options:{maxMacros: 1000, baseURL: "",} | |||
} | |||
d は t {options: {FindTeX: null, packages: Array(3), digits: /^(?:[0-9]+(?:\\{,\\}[0-9]{3})*(?:\\.[0-9]*)?|\\.[0-9]+)/, maxBuffer: 5120, formatError: ƒ, …}, packageData: Map(0) {size: 0}, parsers: {}, root: null, nodeLists: {…}, error : false, handlers t{map : Map(4) {size: 4, character => t {_configura…, …}, delimiter => t {_configura…, …}, macro => t {…}, environment => t {…}}}, itemFactory : e {defaultKind: 'dummy', nodeMap: Map(24), node: {…}, configuration: t}, nodeFactory : t {mmlFactory: null, factory: {…}, configuration: t} } | |||
上記の値は\\とすべきものを\にしています。それでも割かし理解しづらい。 | |||
===== 再び e.MathJax.config.startup.ready() { f() > c } ===== | |||
<syntaxhighlight lang="javascript"> | |||
function e(r) { | |||
void 0 === r && (r = {}); | |||
var n = this, | |||
o = s((0, c.separateOptions)(r, e.OPTIONS, u.FindTeX.OPTIONS), 3), | |||
i = o[0], | |||
a = o[1], | |||
l = o[2]; | |||
(n = t.call(this, a) || this).findTeX = n.options.FindTeX || new u.FindTeX(l); | |||
var h = n.options.packages, | |||
f = n.configuration = e.configure(h), | |||
d = n._parseOptions = new m.default(f, [n.options, y.TagsFactory.OPTIONS]); | |||
return | |||
(0, c.userOptions)(d.options, i), | |||
/* ここから追跡再開 */ | |||
f.config(n), | |||
e.tags(d, f), | |||
n.postFilters.add(p.default. cleanSubSup, -6), | |||
n.postFilters.add(p.default. setInherited, -5), | |||
n.postFilters.add(p.default. moveLimits, -4), | |||
n.postFilters.add(p.default. cleanStretchy, -3), | |||
n.postFilters.add(p.default. cleanAttributes, -2), | |||
n.postFilters.add(p.default.combineRelations, -1), | |||
n | |||
} | |||
</syntaxhighlight> | |||
n は以下のような値になっています。HTMLに定義した config 情報とデフォルト値を結合するような処理が preLoad では処理されています。 | |||
<syntaxhighlight lang="javascript"> | |||
n = | |||
{ | |||
adaptor: null, | |||
mmlFactory: null, | |||
options: { | |||
FindTeX: null, | |||
packages: ["base", "newcommand", "action",], | |||
digits: { }, | |||
maxBuffer: 5120, | |||
formatError: | |||
function(t, e) { | |||
return t.formatError(e) | |||
}, | |||
}, | |||
preFilters: { items: [ ], }, | |||
postFilters: { items: [ ], }, | |||
findTeX: { | |||
options: { | |||
inlineMath : [[ "$", "$",], [ "\\(", "\\)",],], | |||
displayMath: [[ "$$", "$$",], [ "\\[", "\\]",],], | |||
processEscapes: true, | |||
processEnvironments: true, | |||
processRefs: true, | |||
}, | |||
end: { $: [ "$", false, { },], | |||
"\\(": ["\\)", false, { },], | |||
$$: [ "$$", true, { },], | |||
"\\[": ["\\]", true, { },], | |||
}, | |||
sub: 2, | |||
env: 1, | |||
start: { }, | |||
hasPatterns: true, | |||
}, | |||
} | |||
</syntaxhighlight> | |||
f.config(n) で以下の関数が実行されます。t は CONFIG 値 | |||
<syntaxhighlight lang="javascript"> | |||
config = function(t) { | |||
var e, r; | |||
this.configMethod.execute(this, t); | |||
try { | |||
for(var o = n(this.configurations), i = o.next(); !i.done; i = o.next()) { | |||
var s = i.value; | |||
this.addFilters(t, s.item) | |||
} | |||
} catch(t) { | |||
e = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
i && !i.done && (r = o.return) && r.call(o) | |||
} finally { | |||
if(e) throw e.error | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
this.configMethod.execute は以下のような関数です。 | |||
<syntaxhighlight lang="javascript"> | |||
.execute = function() { | |||
for(var t, e, r = [], n = 0; n < arguments.length; n++) | |||
r[n] = arguments[n]; | |||
try { | |||
for(var o = i(this), l = o.next(); !l.done; l = o.next()) { | |||
var c = l.value; | |||
var u = c.item.apply(c, a([], s(r), !1)); | |||
if(!1 === u) return !1 | |||
} | |||
} catch(e) { | |||
t = { | |||
error: e | |||
} | |||
} finally { | |||
try { | |||
l && !l.done && (e = o.return) && e.call(o) | |||
} finally { | |||
if(t) throw t.error | |||
} | |||
} | |||
return !0 | |||
} | |||
</syntaxhighlight> | |||
nを引数に呼び出されますが、excuteでは関数名の横の引数では受け取らず、arguments で制御します。r[n] は r[0] に this 値が、r[1] に n が格納されます。そして try で、呼び出し元のthis 値をひとつづつ取り出して c へ。 | |||
c.item 関数自体にcと2番目の引数を配列のように受け取った結果を返すのが apply です。c.item を thisとすると。c = this(c, 2番目の配列の要素1) → c = this(c, 2番目の配列の要素2) → … → c = this(c, 2番目の配列の要素n) と繰り返し処理されます。a([], [0:{math : e, document : e, data : t }], false) という関数が返す配列です。 | |||
結果的に c = this( c, [0 : {math : { …, …, …, }, document : { …, …, …, }, data : { …, …, …, } });というような処理がされます。結局 preload時は、undefined だそうな。返り値が 0 だと return false が発生します。 | |||
c はこんな関数。とはいいつつも次々と変化します。 | |||
<syntaxhighlight lang="javascript"> | |||
function(t) { | |||
var e = t.data; | |||
e.error || (o(e, "sub", "sup"), o(e, "under", "over")) | |||
} | |||
</syntaxhighlight> | |||
引数の t.data を e に格納して e.error が 0 なら (o(e, "sub", "sup"), o(e, "under", "over")) を実行という感じ。確かに返り値がないね。0 になるときってどんなときなんだろう。この場合はわからん。次の関数とかでなにかおこるのやもしれませんね。 | |||
c を列挙してみます。 | |||
1: | |||
<syntaxhighlight lang="javascript"> | |||
function(t) { | |||
t.data.root.setInheritedAttributes({}, t.math.display, 0, !1) | |||
} | |||
</syntaxhighlight> | |||
2: | |||
<syntaxhighlight lang="javascript"> | |||
function(t) { | |||
var e, r, n = t.data; | |||
try { | |||
for(var o = c(n.getList("nonscript")), i = o.next(); !i.done; i = o.next()) { | |||
var s = i.value; | |||
if(s.attributes.get("scriptlevel") > 0) { | |||
var a = s.parent; | |||
if(a.childNodes.splice(a.childIndex(s), 1), n.removeFromList(s.kind, [s]), s.isKind("mrow")) { | |||
var l = s.childNodes[0]; | |||
n.removeFromList("mstyle", [l]), n.removeFromList("mspace", l.childNodes[0].childNodes) | |||
} | |||
} else s.isKind("mrow") && (s.parent.replaceChild(s.childNodes[0], s), n.removeFromList("mrow", [s])) | |||
} | |||
} catch(t) { | |||
e = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
i && !i.done && (r = o.return) && r.call(o) | |||
} finally { | |||
if(e) throw e.error | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
3: | |||
<syntaxhighlight lang="javascript"> | |||
function(t) { | |||
var e = t.data; | |||
i(e, "munderover", "msubsup"), i(e, "munder", "msub"), i(e, "mover", "msup") | |||
} | |||
</syntaxhighlight> | |||
4: | |||
<syntaxhighlight lang="javascript"> | |||
function(t) { | |||
var e, r, o = t.data; | |||
try { | |||
for(var i = n(o.getList("fixStretchy")), s = i.next(); !s.done; s = i.next()) { | |||
var l = s.value; | |||
if(a.default.getProperty(l, "fixStretchy")) { | |||
var c = a.default.getForm(l); | |||
c && c[3] && c[3].stretchy && a.default.setAttribute(l, "stretchy", !1); | |||
var u = l.parent; | |||
if(!(a.default.getTexClass(l) || c && c[2])) { | |||
var p = o.nodeFactory.create("node", "TeXAtom", [l]); | |||
u.replaceChild(p, l), p.inheritAttributesFrom(l) | |||
} | |||
a.default.removeProperties(l, "fixStretchy") | |||
} | |||
} | |||
} catch(t) { | |||
e = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
s && !s.done && (r = i.return) && r.call(i) | |||
} finally { | |||
if(e) throw e.error | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
5: | |||
<syntaxhighlight lang="javascript"> | |||
function(t) { | |||
t.data.root.walkTree((function(t, e) { | |||
var r, o, i = t.attributes; | |||
if(i) { | |||
var s = new Set((i.get("mjx-keep-attrs") || "").split(/ /)); | |||
delete i.getAllAttributes()["mjx-keep-attrs"]; | |||
try { | |||
for(var a = n(i.getExplicitNames()), l = a.next(); !l.done; l = a.next()) { | |||
var c = l.value; | |||
s.has(c) || i.attributes[c] !== t.attributes.getInherited(c) || delete i.attributes[c] | |||
} | |||
} catch(t) { | |||
r = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
l && !l.done && (o = a.return) && o.call(a) | |||
} finally { | |||
if(r) throw r.error | |||
} | |||
} | |||
} | |||
}), {}) | |||
} | |||
</syntaxhighlight> | |||
6: | |||
<syntaxhighlight lang="javascript"> | |||
{} | |||
</syntaxhighlight> | |||
と、いろいろ処理をします。 | |||
関数は config に戻って、繰り返しの要素変数1-3回目 s は | |||
addFileters(t, s.item) | |||
s = t {name: 'action', handler: {…}, fallback: {…}, items: { }, tags: {…}, …} | |||
t {name: 'newcommand', handler: {…}, fallback: {…}, items: {…}, tags: {…}, …} | |||
t {name: 'base', handler: {…}, fallback: {…}, items: {…}, tags: {…}, …} | |||
t = e {adaptor: null, mmlFactory: null, options: {…}, preFilters: e, postFilters: e, …} | |||
<syntaxhighlight lang="javascript"> | |||
function(t, e) { | |||
var r, i, s, a; | |||
try { | |||
for(var l = n(e.preprocessors), c = l.next(); !c.done; c = l.next()) { | |||
var u = o(c.value, 2), | |||
p = u[0], | |||
h = u[1]; | |||
t.preFilters.add(p, h) | |||
} | |||
} catch(t) { | |||
r = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
c && !c.done && (i = l.return) && i.call(l) | |||
} finally { | |||
if(r) throw r.error | |||
} | |||
} | |||
try { | |||
for(var f = n(e.postprocessors), d = f.next(); !d.done; d = f.next()) { | |||
var m = o(d.value, 2), | |||
y = m[0]; | |||
h = m[1]; | |||
t.postFilters.add(y, h) | |||
} | |||
} catch(t) { | |||
s = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
d && !d.done && (a = f.return) && a.call(f) | |||
} finally { | |||
if(s) throw s.error | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
.preprocessors .postprocessorsも値がないので何も起こらないですね。 | |||
e.tags(d, f) 関数というを処理します。以下のような関数です。 | |||
<syntaxhighlight lang="javascript"> | |||
tags = function(t, e) { | |||
y.TagsFactory.addTags(e.tags), | |||
y.TagsFactory.setDefault(t.options.tags), | |||
t.tags = y.TagsFactory.getDefault(), | |||
t.tags.configuration = t | |||
} | |||
</syntaxhighlight> | |||
このとき d = t, f = e は | |||
t = t {options: {…}, packageData: Map(0), parsers: Array(0), root: null, nodeLists: {…}, …} | |||
e = t {initMethod: e, configMethod: e, configurations: t, parsers: Array(1), handlers: t, tags : {base:{ function() }}} | |||
といった値です。 | |||
<syntaxhighlight lang="javascript"> | |||
y.TagsFactory.addTags = function(e) { | |||
var r, n; | |||
try { | |||
for(var o = i(Object.keys(e)), s = o.next(); !s.done; s = o.next()) { | |||
var a = s.value; | |||
t.add(a, e[a]) | |||
} | |||
} catch(t) { | |||
r = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
s && !s.done && (n = o.return) && n.call(o) | |||
} finally { | |||
if(r) throw r.error | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
e.tags は 関数で以下のようなものです。関数が引数になります。 | |||
<syntaxhighlight lang="javascript"> | |||
{ | |||
base:{ | |||
tags = function() { | |||
return null !== t && t.apply(this, arguments) || this | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
ひとつづつ、t.add(a, e[a]) という処理をする。t.set('base', e['base']) になり、e の base : e['base']が設定される。結果として<syntaxhighlight lang="javascript" inline> e() { return null !== t && t.apply(this, arguments) || this } </syntaxhighlight>が設定される。t に何か設定されていたら、this = t(for (i = arguments; !i.done; i.next())i.value())みたいなことが実行されるってことだな。t の関数がなければthis を返す。 | |||
のこりは | |||
y.TagsFactory.setDefault(t.options.tags), | |||
t.tags = y.TagsFactory.getDefault(), | |||
t.tags.configuration = t | |||
で、y.TagsFactory.setDefault は r = t.options.tags; という処理で、r = 'none' のような処理。 | |||
y.TagsFactory.getDefault() = function() { t.create(r) } は | |||
<syntaxhighlight lang="javascript"> | |||
t.create(t) = function(t) { | |||
var n = e.get(t) || e.get(r); | |||
if(!n) | |||
throw Error("Unknown tags class"); | |||
return new n | |||
} | |||
</syntaxhighlight> | |||
n はこんな関数値です。 | |||
<syntaxhighlight lang="javascript"> | |||
function e() { | |||
return null !== t && t.apply(this, arguments) || this | |||
} | |||
</syntaxhighlight> | |||
他にもメンバ関数 .constructor .autoTag .getTag | |||
.t = funection(){ | |||
this.counter = 0, | |||
this.allCounter = 0, | |||
this.configuration = null, | |||
this.ids = {}, | |||
this.allIds = {}, | |||
this.labels = {}, | |||
this.allLabels = {}, | |||
this.redo = !1, | |||
this.refUpdate = !1, | |||
this.currentTag = new c, | |||
this.history = [], | |||
this.stack = [], | |||
this.enTag = function(t, e) { | |||
var r = this.configuration.nodeFactory, | |||
n = r.create("node", "mtd", [t]), | |||
o = r.create("node", "mlabeledtr", [e, n]); | |||
return r.create( | |||
"node", | |||
"mtable", | |||
[o], | |||
{ | |||
side: this.configuration.options.tagSide, | |||
minlabelspacing: this.configuration.options.tagIndent, | |||
displaystyle: !0 | |||
}) | |||
} | |||
} | |||
がある感じ。 | |||
t { | |||
error : false, | |||
handlers t {map: Map(4)} | |||
itemFactory : e {defaultKind: 'dummy', | |||
nodeMap: Map(24) { | |||
size: 24, | |||
1:start => ƒ e(e, r), | |||
2:stop => ƒ e(), | |||
3:open => ƒ e(), | |||
4:close => ƒ e(), | |||
5:prime => ƒ e(), | |||
6:subsup => ƒ e(), | |||
7:over => ƒ e(), | |||
8:left => ƒ e(), | |||
9:middle => ƒ e(), | |||
10:right => ƒ e(), | |||
11:begin => ƒ e(), | |||
12:end => ƒ e(), | |||
13:style => ƒ e(), | |||
14:position => ƒ e(), | |||
15:cell => ƒ e(), | |||
16:mml => ƒ e(), | |||
17:fn => ƒ e(), | |||
18:not => ƒ e(), | |||
19:nonscript => ƒ e(), | |||
20:dots => ƒ e(), | |||
21:array => ƒ e(), | |||
22:eqnarray => ƒ e(), | |||
23:equation => ƒ e(), | |||
beginEnv => ƒ e(), | |||
…}, | |||
node: {beginEnv: ƒ, start: ƒ, stop: ƒ, open: ƒ, close: ƒ, …}, | |||
configuration: | |||
t {options: {…}, | |||
packageData: [], | |||
parsers: [], | |||
root: null, | |||
nodeLists: {…}, | |||
} | |||
} | |||
nodeFactory : t {mmlFactory: null, factory: {…}, configuration: t} | |||
nodeList | |||
options: { | |||
FindTeX: null, | |||
packages: Array(3), | |||
digits: /^(?:[0-9]+(?:\\{,\\}[0-9]{3})*(?:\\.[0-9]*)?|\\.[0-9]+)/, | |||
maxBuffer: 5120, | |||
formatError: ƒ, …}, | |||
packageData: Map(0) {size: 0}, | |||
parser : ƒ () { | |||
return this.parsers[0] | |||
}, | |||
parsers: [], | |||
root: null, | |||
} | |||
そして最後ですが、 | |||
.add = function(e, r) { | |||
void 0 === r && (r = t.DEFAULTPRIORITY); | |||
var n = this.items.length; | |||
do { | |||
n-- | |||
} while (n >= 0 && r < this.items[n].priority); | |||
return this.items.splice(n + 1, 0, { | |||
item: e, | |||
priority: r | |||
}), e | |||
} | |||
第二引数に優先度が設定されるもので、 e には p.default.cleanSubSup/setInherited/moveLimits/cleanStretchy/cleanAttributes/combineRelationsが設定されます。 | |||
===== e.MathJax.config.startup.ready() { t.defaultReady f() > _() } ===== | |||
次は _ という関数だけど | |||
<syntaxhighlight lang="javascript"> | |||
function _() { | |||
var r = e.CONFIG.output; /* = chtml */ | |||
if(!r) return null; | |||
var n = t.constructors[r]; | |||
if(!n) throw Error('Output Jax "' + r + '" is not defined (has it been loaded?)'); | |||
return new n(e.MathJax.config[r]) | |||
} | |||
</syntaxhighlight> | |||
n = t.constructors['chtml'] で n(e.MathJax.config['chtml']) = {fontURL: 'http://localhost:5500/es5/output/chtml/fonts/woff-v2', font: e} | |||
<syntaxhighlight lang="javascript"> | |||
n = e(e.MathJax.config['chtml']) { | |||
void 0 === e && (e = null); | |||
var r = t.call(this, e, h.CHTMLWrapperFactory, d.TeXFont) || this; | |||
return r.chtmlStyles = null, | |||
r.font.adaptiveCSS(r.options.adaptiveCSS), | |||
r.wrapperUsage = new f.Usage, | |||
r | |||
} | |||
</syntaxhighlight> | |||
これで r が以下のような値になります。 | |||
{ | |||
adaptor : null, | |||
chtmlStyles : null , | |||
cssStyles : t {styles: {cssText : function(){this.getStyleString()}, style : {} } }, | |||
factory : e { defaultKind: 'unknown', | |||
nodeMap: [ | |||
0 : { "math" => function e() { | |||
return null !== t && t.apply(this, arguments) || this | |||
} | |||
}, | |||
1 : { "mrow" => function e() { | |||
return null !== t && t.apply(this, arguments) || this | |||
} | |||
} | |||
2 : { "inferredMrow" = … }, | |||
3 : { "mi" = … }, | |||
4 : { "mo" = … }, | |||
5 : { "mn" = … }, | |||
6 : { "ms" = … }, | |||
7 : { "mtext" = … }, | |||
8 : { "mspace" = … }, | |||
9 : { "mpadded" = … }, | |||
10 : { "menclose" = … }, | |||
11 : { "mfrac" = … }, | |||
12 : { "msqrt" = … }, | |||
13 : { "mroot" = … }, | |||
14 : { "msub" = … }, | |||
15 : { "msup" = … }, | |||
16 : { "msubsup" = … }, | |||
17 : { "munder" = … }, | |||
18 : { "mover" = … }, | |||
19 : { "munderober" = … }, | |||
20 : { "mmultiscripts" = … }, | |||
21 : { "fenced" = … }, | |||
22 : { "mtable" = … }, | |||
23 : { "mtr" = … }, | |||
24 : { "mlabeledtr" = … }, | |||
25 : { "mtd" = … }, | |||
26 : { "maction" = … }, | |||
27 : { "mglyph" = … }, | |||
28 : { "semantics" = … }, | |||
29 : { "annotation" = … }, | |||
30 : { "annotation-xml" = … }, | |||
31 : { "XML" = … }, | |||
32 : { "TeXAtom" = … }, | |||
33 : { "text" = … }, | |||
34 : { "unknown" = … }, | |||
], | |||
node: {mrow : ƒ {}, inferredMrow : …, unknown : ƒ {}}, | |||
jax: e {adaptor: null, | |||
chtmlStyles : null, | |||
font : , | |||
name : , | |||
options : {scale: 1, | |||
minScale: 0.5, | |||
mtextInheritFont: false, | |||
merrorInheritFont: false, | |||
mtextFont: '', | |||
adaptiveCSS : true, | |||
cssStyles : null, | |||
displayAlign : 'center', | |||
displayIndent : '0', | |||
exFactor : 0.5, | |||
font : e {variant: {…}, delimiters: {…}, cssFontMap: {…}, remapChars: {…}, skewIcFactor: 0.75, …} | |||
matchFontHeight : true, | |||
mathmlSpacing : false, | |||
merrorFont : 'serif', | |||
skipAttributes : {}, | |||
wrapperFactory : null, | |||
}, | |||
postFilters : e, | |||
unknownCache : , | |||
factory: e {defaultKind: 'unknown', nodeMap: Map(35), node: {…}, jax: e}, | |||
cssStyles: t {styles: {…}}, … | |||
} | |||
}, | |||
font : e {charUsage : , | |||
cssFamilyPrefix : 'MJXZERO', | |||
cssFontMap : , | |||
delimiters : , | |||
delimUsage : , | |||
options : , | |||
params : { | |||
axis_height : 0.25, | |||
big_op_spacing1 : 0.111, | |||
big_op_spacing2 : 0.167, | |||
big_op_spacing3 : 0.2, | |||
big_op_spaging4 : 0.6, | |||
big_op_spacing5 : 0.1, | |||
delmi1: 2.39, | |||
delmi2 : 1, | |||
delimiterfactor : 901, | |||
delimitershortfall : 0.3, | |||
denom1 : 0.686, | |||
denom2 : 0.345, | |||
extra_ic : 0.033, | |||
min_rule_thickness : 1.25, | |||
nulldelimiterspace : 0.12, | |||
num1 : 0.676, | |||
num2 : 0.394, | |||
num3 : 0.444, | |||
quad : 1, | |||
rule_thickness : 0.06, | |||
scriptspace : 0.05, | |||
separation_factor : 1.75, | |||
sub_drop : 0.05, | |||
sub1 : 0.15, | |||
sub2 : 0.247, | |||
sup_drop : 0.386, | |||
sup1 : 0.413, | |||
sup2 : 0.363, | |||
sup3 : 0.289, | |||
surd_height : 0.075, | |||
x_height : 0.442, | |||
}, | |||
remapChars : , | |||
sizeVariants : , | |||
skewIcFactor : , | |||
stretchVariants : ['-size4'], | |||
styles : , | |||
name : { return this.constructor.NAME }, | |||
options : { | |||
scale : 1, | |||
minScale : 0.5, | |||
mtexInheritFont : false, | |||
mtextFont: '', | |||
adaptiveCSS : true, | |||
displayAlign : 'center', | |||
displayIndent : '0', | |||
exFactor : 0.5, | |||
matchFontHeight : true, | |||
mathmlSpacing : false, | |||
merrorFont : 'serif', | |||
merrorInheritFont : false, | |||
mtexFont : '', | |||
skipAttributes : {}, | |||
wrapperFactory : null | |||
}, | |||
postFilters : e {items : []}, | |||
unknownCache : Map[] {size : 0}, | |||
wrapperUsage : t {used: Set(0), needsUpdate: Array(0)} | |||
===== e.MathJax.config.startup.ready() { t.defaultReady f() > S() } ===== | |||
<syntaxhighlight lang="javascript"> | |||
S = function(){ | |||
var r = e.CONFIG.adaptor; /* 'browserAdaptor' */ | |||
if(!r || "none" === r) return null; | |||
var n = t.constructors[r]; | |||
if(!n) throw Error('DOMAdaptor "' + r + '" is not defined (has it been loaded?)'); | |||
return n(e.MathJax.config[r]) | |||
} | |||
</syntaxhighlight> | |||
n は function() { return new n.HTMLAdaptor(window) } となります。この n に e.MathJax.config['browserAdaptor'] のような値を引数にして実行したものを返します。undefined でした。返却されるのは e {document: #document, window: Window, parser: DOMParser} のような値です。 | |||
t.input = v(), t.output = _(), t.adaptor = S() だけで、まぁ、長かったな。 | |||
t.handler && l.handlers.unregister(t.handler) | |||
===== e.MathJax.config.startup.ready() { t.defaultReady f() > M() } ===== | |||
t.handlers に格納されるために実行する M() は、以下のような関数です。 | |||
<syntaxhighlight lang="javascript"> | |||
M = function(){ | |||
var r, n, i = e.CONFIG.handler; /* 'HTMLHandler' */ | |||
if(!i || "none" === i || !t.adaptor) return null; | |||
var s = t.constructors[i]; | |||
if(!s) throw Error('Handler "' + i + '" is not defined (has it been loaded?)'); | |||
var a = new s(t.adaptor, 5); | |||
try { | |||
for(var l = o(u), c = l.next(); !c.done; c = l.next()) { | |||
a = c.value.item(a) | |||
} | |||
} catch(t) { | |||
r = { | |||
error: t | |||
} | |||
} finally { | |||
try { | |||
c && !c.done && (n = l.return) && n.call(l) | |||
} finally { | |||
if(r) throw r.error | |||
} | |||
} | |||
return a | |||
} | |||
</syntaxhighlight> | |||
e.CONFIG.handler は何も設定されていなければ null を返しますが、 'HTMLHandler' がされていますので、処理は継続されます。 | |||
<syntaxhighlight lang="javascript"> | |||
t.constructors[i] = function(){ | |||
var e = null !== t && t.apply(this, arguments) || this; | |||
return e.documentClass = s.HTMLDocument, e | |||
} | |||
</syntaxhighlight> | |||
をt.adaptor, 5という引数で実行し、その後のfor文で使うための値を a に取得します。t 関数で this = t(this, t.adaptor) → this = t(this, 5) という値を算出して e に格納します。この時の t は呼び出されたときの t とは異なる値です。以下のような関数です。 | |||
<syntaxhighlight lang="javascript"> | |||
t(t, e) { | |||
void 0 === e && (e = 5), /* e = 0 なら 5 に修正、その他の値ならそのまま。 */ | |||
this.documentClass = i, | |||
this.adaptor = t, /* t.adpter */ | |||
this.priority = e /* 第二引数 */ | |||
} | |||
</syntaxhighlight> | |||
i はfunction() { return null !== t && t.apply(this, arguments) || this } このような関数です。これが this.documentClass に格納します。 | |||
そして e.documentClass = s.HTMLDocument に設定されていますので、この i は上書きされているように思えます。そのようにした e を返しているので、 e は 以下のような値になっていると思います。 | |||
e {documentClass => | |||
{function() = s.HTMLDocument = function e(e, r, n) { | |||
var o = this, | |||
i = s((0, c.separateOptions)(n, h.HTMLDomStrings.OPTIONS), 2), | |||
a = i[0], | |||
l = i[1]; | |||
return(o = t.call(this, e, r, a) || this).domStrings = o.options.DomStrings || | |||
new h.HTMLDomStrings(l), | |||
o.domStrings.adaptor = r, | |||
o.styles = [], | |||
o | |||
} | |||
}, | |||
KIND : 'HTML' | |||
OPTIONS:{OutputJax: null, | |||
InputJax: null, | |||
MmlFactory: null, | |||
MathList: e() {return null !== t && t.apply(this, arguments) || this}, | |||
MathItem: e(e, r, n, o, i) { | |||
return void 0 === n && | |||
(n = !0), | |||
void 0 === o && | |||
(o = { | |||
node: null, | |||
n: 0, | |||
delim: "" | |||
}), | |||
void 0 === i && | |||
(i = { | |||
node: null, | |||
n: 0, | |||
delim: "" | |||
}), | |||
t.call(this, e, r, n, o, i) || this | |||
}, | |||
compileError : ƒ, | |||
DomStrings : null, | |||
renderAction : a {find: [ 10, 'findMath', '', false], | |||
compile: [ 20], | |||
metrics: [ 100, getMetrics, '', false], | |||
typeset: [150], | |||
update: [ 200, 'updateDocument', false], | |||
styles: [ 201, '', 'updateStyleSheet, false], | |||
}, | |||
typesetError : ƒ, | |||
} | |||
}, | |||
adaptor: e {document: #document, window: Window, parser: DOMParser}, | |||
priority: 5 | |||
} | |||
上記の値が e を経由して a に格納され、返されます。for文でo(u)の繰り返しで得られる要素c.value.item(a)の最後の処理がaに格納されます。 | |||
o(u)は2つの要素を持ちますが、最初は | |||
function(t) { | |||
return(0, _n.AssistiveMmlHandler)(t) | |||
} | |||
<syntaxhighlight lang="javascript"> | |||
AssistiveMmlHandler = function(t) { | |||
return t.documentClass = d(t.documentClass), | |||
t | |||
} | |||
</syntaxhighlight> | |||
次は | |||
function(t) { | |||
return(0, gn.MenuHandler)(t) | |||
} | |||
で、a には gn.MenuHandler)(a)という値が得られる。 | |||
gn.MenuHandlerは以下のような関数 | |||
<syntaxhighlight lang="javascript"> | |||
function(t) { | |||
return t.documentClass = d(t.documentClass), | |||
t | |||
} | |||
</syntaxhighlight> | |||
d は | |||
<syntaxhighlight lang="javascript"> | |||
function d(t) { | |||
var e; | |||
return e = function(t) { /* run */ | |||
function e() { | |||
for(var e = [], r = 0; r < arguments.length; r++) e[r] = arguments[r]; | |||
var n = t.apply(this, a([], s(e), !1)) || this; | |||
n.menu = new n.options.MenuClass(n, n.options.menuOptions); | |||
var o = n.constructor.ProcessBits; | |||
return o.has("context-menu") || o.allocate("context-menu"), n.options.MathItem = f(n.options.MathItem), n | |||
} | |||
return o(e, t), e.prototype.addMenu = function() { /* run */ | |||
var t, e; | |||
if(!this.processed.isSet("context-menu")) { | |||
try { | |||
for(var r = l(this.math), n = r.next(); !n.done; n = r.next()) { | |||
n.value.addMenu(this) | |||
} | |||
} catch(e) { | |||
t = { | |||
error: e | |||
} | |||
} finally { | |||
try { | |||
n && !n.done && (e = r.return) && e.call(r) | |||
} finally { | |||
if(t) throw t.error | |||
} | |||
} | |||
this.processed.set("context-menu") | |||
} | |||
return this | |||
}, e.prototype.checkLoading = function() { | |||
this.menu.isLoading && c.mathjax.retryAfter(this.menu.loadingPromise.catch((function(t) { | |||
return console.log(t) | |||
}))); | |||
var t = this.menu.settings; | |||
return t.collapsible && (this.options.enableComplexity = !0, this.menu.checkComponent("a11y/complexity")), t.explorer && (this.options.enableEnrichment = !0, this.options.enableExplorer = !0, this.menu.checkComponent("a11y/explorer")), this | |||
}, e.prototype.state = function(e, r) { | |||
return void 0 === r && (r = !1), t.prototype.state.call(this, e, r), e < u.STATE.CONTEXT_MENU && this.processed.clear("context-menu"), this | |||
}, e.prototype.updateDocument = function() { | |||
return t.prototype.updateDocument.call(this), this.menu.menu.store.sort(), this | |||
}, e | |||
}(t), e.OPTIONS = i(i({ | |||
enableEnrichment: !0, | |||
enableComplexity: !0, | |||
enableExplorer: !0, | |||
enrichSpeech: "none", | |||
enrichError: function(t, e, r) { | |||
return console.warn("Enrichment Error:", r) | |||
} | |||
}, t.OPTIONS), { | |||
MenuClass: h.Menu, | |||
menuOptions: h.Menu.OPTIONS, | |||
enableMenu: !0, | |||
sre: t.OPTIONS.sre || (0, p.expandable)({}), | |||
a11y: t.OPTIONS.a11y || (0, p.expandable)({}), | |||
renderActions: (0, p.expandable)(i(i({}, t.OPTIONS.renderActions), { | |||
addMenu: [u.STATE.CONTEXT_MENU], | |||
checkLoading: [u.STATE.UNPROCESSED + 1] | |||
})) | |||
}), e | |||
} | |||
</syntaxhighlight> | |||
結果、以下のような値になります。 | |||
e { | |||
documentClass: { | |||
function e() { | |||
for(var e = [], r = 0; r < arguments.length; r++) | |||
e[r] = arguments[r]; | |||
var n = t.apply(this, a([], s(e), !1)) || this; | |||
n.menu = new n.options.MenuClass(n, n.options.menuOptions); | |||
var o = n.constructor.ProcessBits; | |||
return o.has("context-menu") || | |||
o.allocate("context-menu"), | |||
n.options.MathItem = f(n.options.MathItem), | |||
n | |||
}, | |||
{ | |||
a11y: a, | |||
compilerError: ƒ | |||
DomStrings: null, | |||
enableAssistveMml: true, | |||
enableEnrichment: true, | |||
enableComplexity: true, | |||
enableExplorer: true, | |||
enableMenu: true, | |||
enrichSpeech: 'none', | |||
enrichError: ƒ, | |||
InputJax: null, | |||
MathItem: ƒ, | |||
MathList:, | |||
MenuClass:, | |||
menuOptions: { | |||
settings: { | |||
texHints: true, | |||
semantics: false, | |||
zoom: 'NoZoom', | |||
zscale: '200%', | |||
renderer: 'CHTML', … | |||
}, | |||
jax: {CHTML: null, SVG: null}, | |||
annotationTypes: a | |||
}, | |||
MmlFactory: null, | |||
OutputJax: null, | |||
renderActions: a { | |||
find: Array(4), | |||
compile: Array(1), | |||
metrics: Array(4), | |||
typeset: Array(1), | |||
update: Array(3), … | |||
} | |||
} | |||
} | |||
adaptor: e, | |||
priority: 5 | |||
} | |||
シンプルなようで非常に複雑です。謎めいた処理です。また後程確認をするとしましょう。 | |||
===== e.MathJax.config.startup.ready() { t.defaultReady f() > O() } ===== | |||
<syntaxhighlight lang="javascript"> | |||
function O(r) { | |||
return void 0 === r && | |||
(r = null), | |||
l.document( | |||
r || | |||
e.CONFIG.document, | |||
n( | |||
n( {}, e.MathJax.config.options), | |||
{ | |||
InputJax: t.input, | |||
OutputJax: t.output | |||
} | |||
) | |||
) | |||
} | |||
</syntaxhighlight> | |||
r = 0 なら、r = nullとして、返却値の対象の l.document(e.CONFIG.document, n())の演算を行います。以下のような値が返ってきます。 | |||
e { | |||
adaptor: , | |||
document: #document, | |||
domStrings: , | |||
inputJax: [e, e], | |||
kind: | |||
options: {…}, | |||
math: e {list: s}, | |||
menu: , | |||
mmlFactory: , | |||
outputJax: , | |||
processed: e, | |||
renderActions: e, | |||
styles: , | |||
vistor | |||
} | |||
l.document(t,r) は次のような関数です。function(t, r) { return e.mathjax.handlers.document(t, r) } で t はe.CONFIG.document です。r は演算されて {InputJax: [e, e], OutputJax: e} といった内容になります。 | |||
Input の e は e {adaptor: e, mmlFactory: e, options: {…}, preFilters: e, postFilters: e, …}、Output の e は e {adaptor: e, options: {…}, postFilters: e, factory: e, cssStyles: t, …} のようなものです。 | |||
=== ページ === | |||
*次:[[MathJaxをデバッグしてJavaScriptの理解を深める ページ2]] | |||
*[[MathJaxをデバッグしてJavaScriptの理解を深める ページ3]] | |||
*[[MathJaxをデバッグしてJavaScriptの理解を深める ページ4]] | |||
2022年12月9日 (金) 16:44時点における最新版
概要
JavaScriptで書かれたMathJaxライブラリは、TeXのような組版処理をサービスを提供しているCDN(Content Delivery Network:コンテンツ配信サービス)あるいは自前のサーバーに配置するかするようにして構築するものです。主に数式の組版をするために提供されているサービスです。
このような組版処理はいくらやってもらってもいいという感じで、楽譜とかも組版出来たらいいのにと夢みたいなことをおもっていたのですが、一部には実際に楽譜が組めるようになっているサービスもあるようですが、なっとくいかない仕上がりです。納得しろやオマエ。って思うでしょ。そうなんすよ。作れないくせになっとくしてないんすよ。もっとやりたいことは簡単な楽譜処理なんすよ。そういうのはおいといて、数式の組版を実現したMathJaxはスゴイと思います。それで、これを理解したら自分にも役に立つJavaScriptが作れるようになるんじゃないかと思ったりしました。JavaScript初心者ですよ。
MathJaxに使われている技術を理解してく記事です。途中まで読み進めるだけで充分そのエッセンスを吸収できると思いますので、全てを解析するのではなく、途中まで読んでみるというものです。期待し過ぎないで下さい。結果的にJAVA Scriptのページのリファレンスが少しだけ実用レベルのリファレンスくらいに充実するということを狙っています。そして理解するための工夫や解析によってわかったMathJaxの考え方をここで書いていきます。自分が使ったことのあるのはMathJaxの中の/es5/tex-mml-chtml.jsで、これをちょろっと覗くとまぁエグイ。こういうのを覘くっていうんだっけ?一行目で終わってるプログラム。さすが、一行の長さがエグイ。インデントしてみたら5万行にもわたるプログラムが1行になってる。改行なしのプログラムあるんだなぁ。
ちなみに解の公式のサンプルは以下のような結果を得るためのライブラリだ。
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width">
<title>MathJax v3 with customized list of components</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script>
MathJax = {
loader: {
load: ['input/tex-base', '[tex]/newcommand', '[tex]/action', 'output/chtml']
},
tex: {
inlineMath: [
['$', '$'],
['\\(', '\\)']
],
packages: ['base', 'newcommand', 'action']
}
};
</script>
<script id="MathJax-script" async="" src="../es5/tex-mml-chtml.js"></script>
<script src="file:///C:/MathJax/es5/input/tex/extensions/action.js" charset="UTF-8"></script>
<style type="text/css">
.CtxtMenu_InfoClose {
top: .2em;
right: .2em;
}
.CtxtMenu_InfoContent {
overflow: auto;
text-align: left;
font-size: 80%;
padding: .4em .6em;
border: 1px inset;
margin: 1em 0px;
max-height: 20em;
max-width: 30em;
background-color: #EEEEEE;
white-space: normal;
}
.CtxtMenu_Info.CtxtMenu_MousePost {
outline: none;
}
.CtxtMenu_Info {
position: fixed;
left: 50%;
width: auto;
text-align: center;
border: 3px outset;
padding: 1em 2em;
background-color: #DDDDDD;
color: black;
cursor: default;
font-family: message-box;
font-size: 120%;
font-style: normal;
text-indent: 0;
text-transform: none;
line-height: normal;
letter-spacing: normal;
word-spacing: normal;
word-wrap: normal;
white-space: nowrap;
float: none;
z-index: 201;
border-radius: 15px;
/* Opera 10.5 and IE9 */
-webkit-border-radius: 15px;
/* Safari and Chrome */
-moz-border-radius: 15px;
/* Firefox */
-khtml-border-radius: 15px;
/* Konqueror */
box-shadow: 0px 10px 20px #808080;
/* Opera 10.5 and IE9 */
-webkit-box-shadow: 0px 10px 20px #808080;
/* Safari 3 & Chrome */
-moz-box-shadow: 0px 10px 20px #808080;
/* Forefox 3.5 */
-khtml-box-shadow: 0px 10px 20px #808080;
/* Konqueror */
filter: progid: DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color="gray", Positive="true");
/* IE */
}
</style>
<style type="text/css">
.CtxtMenu_MenuClose {
position: absolute;
cursor: pointer;
display: inline-block;
border: 2px solid #AAA;
border-radius: 18px;
-webkit-border-radius: 18px;
/* Safari and Chrome */
-moz-border-radius: 18px;
/* Firefox */
-khtml-border-radius: 18px;
/* Konqueror */
font-family: "Courier New", Courier;
font-size: 24px;
color: #F0F0F0
}
.CtxtMenu_MenuClose span {
display: block;
background-color: #AAA;
border: 1.5px solid;
border-radius: 18px;
-webkit-border-radius: 18px;
/* Safari and Chrome */
-moz-border-radius: 18px;
/* Firefox */
-khtml-border-radius: 18px;
/* Konqueror */
line-height: 0;
padding: 8px 0 6px/* may need to be browser-specific */
}
.CtxtMenu_MenuClose:hover {
color: white!important;
border: 2px solid #CCC!important
}
.CtxtMenu_MenuClose:hover span {
background-color: #CCC!important
}
.CtxtMenu_MenuClose:hover:focus {
outline: none
}
</style>
<style type="text/css">
.CtxtMenu_Menu {
position: absolute;
background-color: white;
color: black;
width: auto;
padding: 5px 0px;
border: 1px solid #CCCCCC;
margin: 0;
cursor: default;
font: menu;
text-align: left;
text-indent: 0;
text-transform: none;
line-height: normal;
letter-spacing: normal;
word-spacing: normal;
word-wrap: normal;
white-space: nowrap;
float: none;
z-index: 201;
border-radius: 5px;
/* Opera 10.5 and IE9 */
-webkit-border-radius: 5px;
/* Safari and Chrome */
-moz-border-radius: 5px;
/* Firefox */
-khtml-border-radius: 5px;
/* Konqueror */
box-shadow: 0px 10px 20px #808080;
/* Opera 10.5 and IE9 */
-webkit-box-shadow: 0px 10px 20px #808080;
/* Safari 3 & Chrome */
-moz-box-shadow: 0px 10px 20px #808080;
/* Forefox 3.5 */
-khtml-box-shadow: 0px 10px 20px #808080;
/* Konqueror */
}
.CtxtMenu_MenuItem {
padding: 1px 2em;
background: transparent;
}
.CtxtMenu_MenuArrow {
position: absolute;
right: .5em;
padding-top: .25em;
color: #666666;
font-family: null;
font-size: .75em
}
.CtxtMenu_MenuActive .CtxtMenu_MenuArrow {
color: white
}
.CtxtMenu_MenuArrow.CtxtMenu_RTL {
left: .5em;
right: auto
}
.CtxtMenu_MenuCheck {
position: absolute;
left: .7em;
font-family: null
}
.CtxtMenu_MenuCheck.CtxtMenu_RTL {
right: .7em;
left: auto
}
.CtxtMenu_MenuRadioCheck {
position: absolute;
left: .7em;
}
.CtxtMenu_MenuRadioCheck.CtxtMenu_RTL {
right: .7em;
left: auto
}
.CtxtMenu_MenuInputBox {
padding-left: 1em;
right: .5em;
color: #666666;
font-family: null;
}
.CtxtMenu_MenuInputBox.CtxtMenu_RTL {
left: .1em;
}
.CtxtMenu_MenuComboBox {
left: .1em;
padding-bottom: .5em;
}
.CtxtMenu_MenuSlider {
left: .1em;
}
.CtxtMenu_SliderValue {
position: absolute;
right: .1em;
padding-top: .25em;
color: #333333;
font-size: .75em
}
.CtxtMenu_SliderBar {
outline: none;
background: #d3d3d3
}
.CtxtMenu_MenuLabel {
padding: 1px 2em 3px 1.33em;
font-style: italic
}
.CtxtMenu_MenuRule {
border-top: 1px solid #DDDDDD;
margin: 4px 3px;
}
.CtxtMenu_MenuDisabled {
color: GrayText
}
.CtxtMenu_MenuActive {
background-color: #606872;
color: white;
}
.CtxtMenu_MenuDisabled:focus {
background-color: #E8E8E8
}
.CtxtMenu_MenuLabel:focus {
background-color: #E8E8E8
}
.CtxtMenu_ContextMenu:focus {
outline: none
}
.CtxtMenu_ContextMenu .CtxtMenu_MenuItem:focus {
outline: none
}
.CtxtMenu_SelectionMenu {
position: relative;
float: left;
border-bottom: none;
-webkit-box-shadow: none;
-webkit-border-radius: 0px;
}
.CtxtMenu_SelectionItem {
padding-right: 1em;
}
.CtxtMenu_Selection {
right: 40%;
width: 50%;
}
.CtxtMenu_SelectionBox {
padding: 0em;
max-height: 20em;
max-width: none;
background-color: #FFFFFF;
}
.CtxtMenu_SelectionDivider {
clear: both;
border-top: 2px solid #000000;
}
.CtxtMenu_Menu .CtxtMenu_MenuClose {
top: -10px;
left: -10px
}
</style>
<style id="MJX-CHTML-styles">
mjx-container[jax="CHTML"] {
line-height: 0;
}
mjx-container [space="1"] {
margin-left: .111em;
}
mjx-container [space="2"] {
margin-left: .167em;
}
mjx-container [space="3"] {
margin-left: .222em;
}
mjx-container [space="4"] {
margin-left: .278em;
}
mjx-container [space="5"] {
margin-left: .333em;
}
mjx-container [rspace="1"] {
margin-right: .111em;
}
mjx-container [rspace="2"] {
margin-right: .167em;
}
mjx-container [rspace="3"] {
margin-right: .222em;
}
mjx-container [rspace="4"] {
margin-right: .278em;
}
mjx-container [rspace="5"] {
margin-right: .333em;
}
mjx-container [size="s"] {
font-size: 70.7%;
}
mjx-container [size="ss"] {
font-size: 50%;
}
mjx-container [size="Tn"] {
font-size: 60%;
}
mjx-container [size="sm"] {
font-size: 85%;
}
mjx-container [size="lg"] {
font-size: 120%;
}
mjx-container [size="Lg"] {
font-size: 144%;
}
mjx-container [size="LG"] {
font-size: 173%;
}
mjx-container [size="hg"] {
font-size: 207%;
}
mjx-container [size="HG"] {
font-size: 249%;
}
mjx-container [width="full"] {
width: 100%;
}
mjx-box {
display: inline-block;
}
mjx-block {
display: block;
}
mjx-itable {
display: inline-table;
}
mjx-row {
display: table-row;
}
mjx-row > * {
display: table-cell;
}
mjx-mtext {
display: inline-block;
}
mjx-mstyle {
display: inline-block;
}
mjx-merror {
display: inline-block;
color: red;
background-color: yellow;
}
mjx-mphantom {
visibility: hidden;
}
_::-webkit-full-page-media,
_:future,
:root mjx-container {
will-change: opacity;
}
mjx-assistive-mml {
position: absolute !important;
top: 0px;
left: 0px;
clip: rect(1px, 1px, 1px, 1px);
padding: 1px 0px 0px 0px !important;
border: 0px !important;
display: block !important;
width: auto !important;
overflow: hidden !important;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
mjx-assistive-mml[display="block"] {
width: 100% !important;
}
mjx-math {
display: inline-block;
text-align: left;
line-height: 0;
text-indent: 0;
font-style: normal;
font-weight: normal;
font-size: 100%;
font-size-adjust: none;
letter-spacing: normal;
border-collapse: collapse;
word-wrap: normal;
word-spacing: normal;
white-space: nowrap;
direction: ltr;
padding: 1px 0;
}
mjx-container[jax="CHTML"][display="true"] {
display: block;
text-align: center;
margin: 1em 0;
}
mjx-container[jax="CHTML"][display="true"][width="full"] {
display: flex;
}
mjx-container[jax="CHTML"][display="true"] mjx-math {
padding: 0;
}
mjx-container[jax="CHTML"][justify="left"] {
text-align: left;
}
mjx-container[jax="CHTML"][justify="right"] {
text-align: right;
}
mjx-mi {
display: inline-block;
text-align: left;
}
mjx-c {
display: inline-block;
}
mjx-utext {
display: inline-block;
padding: .75em 0 .2em 0;
}
mjx-mo {
display: inline-block;
text-align: left;
}
mjx-stretchy-h {
display: inline-table;
width: 100%;
}
mjx-stretchy-h > * {
display: table-cell;
width: 0;
}
mjx-stretchy-h > * > mjx-c {
display: inline-block;
transform: scalex(1.0000001);
}
mjx-stretchy-h > * > mjx-c::before {
display: inline-block;
width: initial;
}
mjx-stretchy-h > mjx-ext {
/* IE */
overflow: hidden;
/* others */
overflow: clip visible;
width: 100%;
}
mjx-stretchy-h > mjx-ext > mjx-c::before {
transform: scalex(500);
}
mjx-stretchy-h > mjx-ext > mjx-c {
width: 0;
}
mjx-stretchy-h > mjx-beg > mjx-c {
margin-right: -.1em;
}
mjx-stretchy-h > mjx-end > mjx-c {
margin-left: -.1em;
}
mjx-stretchy-v {
display: inline-block;
}
mjx-stretchy-v > * {
display: block;
}
mjx-stretchy-v > mjx-beg {
height: 0;
}
mjx-stretchy-v > mjx-end > mjx-c {
display: block;
}
mjx-stretchy-v > * > mjx-c {
transform: scaley(1.0000001);
transform-origin: left center;
overflow: hidden;
}
mjx-stretchy-v > mjx-ext {
display: block;
height: 100%;
box-sizing: border-box;
border: 0px solid transparent;
/* IE */
overflow: hidden;
/* others */
overflow: visible clip;
}
mjx-stretchy-v > mjx-ext > mjx-c::before {
width: initial;
box-sizing: border-box;
}
mjx-stretchy-v > mjx-ext > mjx-c {
transform: scaleY(500) translateY(.075em);
overflow: visible;
}
mjx-mark {
display: inline-block;
height: 0px;
}
mjx-mn {
display: inline-block;
text-align: left;
}
mjx-msup {
display: inline-block;
text-align: left;
}
mjx-TeXAtom {
display: inline-block;
text-align: left;
}
mjx-mfrac {
display: inline-block;
text-align: left;
}
mjx-frac {
display: inline-block;
vertical-align: 0.17em;
padding: 0 .22em;
}
mjx-frac[type="d"] {
vertical-align: .04em;
}
mjx-frac[delims] {
padding: 0 .1em;
}
mjx-frac[atop] {
padding: 0 .12em;
}
mjx-frac[atop][delims] {
padding: 0;
}
mjx-dtable {
display: inline-table;
width: 100%;
}
mjx-dtable > * {
font-size: 2000%;
}
mjx-dbox {
display: block;
font-size: 5%;
}
mjx-num {
display: block;
text-align: center;
}
mjx-den {
display: block;
text-align: center;
}
mjx-mfrac[bevelled] > mjx-num {
display: inline-block;
}
mjx-mfrac[bevelled] > mjx-den {
display: inline-block;
}
mjx-den[align="right"],
mjx-num[align="right"] {
text-align: right;
}
mjx-den[align="left"],
mjx-num[align="left"] {
text-align: left;
}
mjx-nstrut {
display: inline-block;
height: .054em;
width: 0;
vertical-align: -.054em;
}
mjx-nstrut[type="d"] {
height: .217em;
vertical-align: -.217em;
}
mjx-dstrut {
display: inline-block;
height: .505em;
width: 0;
}
mjx-dstrut[type="d"] {
height: .726em;
}
mjx-line {
display: block;
box-sizing: border-box;
min-height: 1px;
height: .06em;
border-top: .06em solid;
margin: .06em -.1em;
overflow: hidden;
}
mjx-line[type="d"] {
margin: .18em -.1em;
}
mjx-mrow {
display: inline-block;
text-align: left;
}
mjx-msqrt {
display: inline-block;
text-align: left;
}
mjx-root {
display: inline-block;
white-space: nowrap;
}
mjx-surd {
display: inline-block;
vertical-align: top;
}
mjx-sqrt {
display: inline-block;
padding-top: .07em;
}
mjx-sqrt > mjx-box {
border-top: .07em solid;
}
mjx-sqrt.mjx-tall > mjx-box {
padding-left: .3em;
margin-left: -.3em;
}
mjx-maction {
display: inline-block;
text-align: left;
position: relative;
}
mjx-maction > mjx-tool {
display: none;
position: absolute;
bottom: 0;
right: 0;
width: 0;
height: 0;
z-index: 500;
}
mjx-tool > mjx-tip {
display: inline-block;
padding: .2em;
border: 1px solid #888;
font-size: 70%;
background-color: #F8F8F8;
color: black;
box-shadow: 2px 2px 5px #AAAAAA;
}
mjx-maction[toggle] {
cursor: pointer;
}
mjx-status {
display: block;
position: fixed;
left: 1em;
bottom: 1em;
min-width: 25%;
padding: .2em .4em;
border: 1px solid #888;
font-size: 90%;
background-color: #F8F8F8;
color: black;
}
mjx-c::before {
display: block;
width: 0;
}
.MJX-TEX {
font-family: MJXZERO, MJXTEX;
}
.TEX-B {
font-family: MJXZERO, MJXTEX-B;
}
.TEX-I {
font-family: MJXZERO, MJXTEX-I;
}
.TEX-MI {
font-family: MJXZERO, MJXTEX-MI;
}
.TEX-BI {
font-family: MJXZERO, MJXTEX-BI;
}
.TEX-S1 {
font-family: MJXZERO, MJXTEX-S1;
}
.TEX-S2 {
font-family: MJXZERO, MJXTEX-S2;
}
.TEX-S3 {
font-family: MJXZERO, MJXTEX-S3;
}
.TEX-S4 {
font-family: MJXZERO, MJXTEX-S4;
}
.TEX-A {
font-family: MJXZERO, MJXTEX-A;
}
.TEX-C {
font-family: MJXZERO, MJXTEX-C;
}
.TEX-CB {
font-family: MJXZERO, MJXTEX-CB;
}
.TEX-FR {
font-family: MJXZERO, MJXTEX-FR;
}
.TEX-FRB {
font-family: MJXZERO, MJXTEX-FRB;
}
.TEX-SS {
font-family: MJXZERO, MJXTEX-SS;
}
.TEX-SSB {
font-family: MJXZERO, MJXTEX-SSB;
}
.TEX-SSI {
font-family: MJXZERO, MJXTEX-SSI;
}
.TEX-SC {
font-family: MJXZERO, MJXTEX-SC;
}
.TEX-T {
font-family: MJXZERO, MJXTEX-T;
}
.TEX-V {
font-family: MJXZERO, MJXTEX-V;
}
.TEX-VB {
font-family: MJXZERO, MJXTEX-VB;
}
mjx-stretchy-v mjx-c,
mjx-stretchy-h mjx-c {
font-family: MJXZERO, MJXTEX-S1, MJXTEX-S4, MJXTEX, MJXTEX-A ! important;
}
@font-face
/* 0 */
{
font-family: MJXZERO;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Zero.woff") format("woff");
}
@font-face
/* 1 */
{
font-family: MJXTEX;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Main-Regular.woff") format("woff");
}
@font-face
/* 2 */
{
font-family: MJXTEX-B;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Main-Bold.woff") format("woff");
}
@font-face
/* 3 */
{
font-family: MJXTEX-I;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Math-Italic.woff") format("woff");
}
@font-face
/* 4 */
{
font-family: MJXTEX-MI;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Main-Italic.woff") format("woff");
}
@font-face
/* 5 */
{
font-family: MJXTEX-BI;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Math-BoldItalic.woff") format("woff");
}
@font-face
/* 6 */
{
font-family: MJXTEX-S1;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Size1-Regular.woff") format("woff");
}
@font-face
/* 7 */
{
font-family: MJXTEX-S2;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Size2-Regular.woff") format("woff");
}
@font-face
/* 8 */
{
font-family: MJXTEX-S3;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Size3-Regular.woff") format("woff");
}
@font-face
/* 9 */
{
font-family: MJXTEX-S4;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Size4-Regular.woff") format("woff");
}
@font-face
/* 10 */
{
font-family: MJXTEX-A;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_AMS-Regular.woff") format("woff");
}
@font-face
/* 11 */
{
font-family: MJXTEX-C;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Regular.woff") format("woff");
}
@font-face
/* 12 */
{
font-family: MJXTEX-CB;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Bold.woff") format("woff");
}
@font-face
/* 13 */
{
font-family: MJXTEX-FR;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Fraktur-Regular.woff") format("woff");
}
@font-face
/* 14 */
{
font-family: MJXTEX-FRB;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Fraktur-Bold.woff") format("woff");
}
@font-face
/* 15 */
{
font-family: MJXTEX-SS;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_SansSerif-Regular.woff") format("woff");
}
@font-face
/* 16 */
{
font-family: MJXTEX-SSB;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_SansSerif-Bold.woff") format("woff");
}
@font-face
/* 17 */
{
font-family: MJXTEX-SSI;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_SansSerif-Italic.woff") format("woff");
}
@font-face
/* 18 */
{
font-family: MJXTEX-SC;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Script-Regular.woff") format("woff");
}
@font-face
/* 19 */
{
font-family: MJXTEX-T;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Typewriter-Regular.woff") format("woff");
}
@font-face
/* 20 */
{
font-family: MJXTEX-V;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Vector-Regular.woff") format("woff");
}
@font-face
/* 21 */
{
font-family: MJXTEX-VB;
src: url("file:///C:/MathJax/es5/output/chtml/fonts/woff-v2/MathJax_Vector-Bold.woff") format("woff");
}
mjx-c.mjx-c1D44E.TEX-I::before {
padding: 0.441em 0.529em 0.01em 0;
content: "a";
}
mjx-c.mjx-c2260::before {
padding: 0.716em 0.778em 0.215em 0;
content: "\2260";
}
mjx-c.mjx-c30::before {
padding: 0.666em 0.5em 0.022em 0;
content: "0";
}
mjx-c.mjx-c1D465.TEX-I::before {
padding: 0.442em 0.572em 0.011em 0;
content: "x";
}
mjx-c.mjx-c32::before {
padding: 0.666em 0.5em 0 0;
content: "2";
}
mjx-c.mjx-c2B::before {
padding: 0.583em 0.778em 0.082em 0;
content: "+";
}
mjx-c.mjx-c1D44F.TEX-I::before {
padding: 0.694em 0.429em 0.011em 0;
content: "b";
}
mjx-c.mjx-c1D450.TEX-I::before {
padding: 0.442em 0.433em 0.011em 0;
content: "c";
}
mjx-c.mjx-c3D::before {
padding: 0.583em 0.778em 0.082em 0;
content: "=";
}
mjx-c.mjx-c2212::before {
padding: 0.583em 0.778em 0.082em 0;
content: "\2212";
}
mjx-c.mjx-cB1::before {
padding: 0.666em 0.778em 0 0;
content: "\B1";
}
mjx-c.mjx-c221A::before {
padding: 0.8em 0.853em 0.2em 0;
content: "\221A";
}
mjx-c.mjx-c34::before {
padding: 0.677em 0.5em 0 0;
content: "4";
}
mjx-c.mjx-c2E::before {
padding: 0.12em 0.278em 0 0;
content: ".";
}
</style>
</head>
<body>
<mjx-container class="MathJax CtxtMenu_Attached_0" jax="CHTML" display="true" tabindex="0" ctxtmenu_counter="2" style="font-size: 124.9%; position: relative;">
<mjx-math display="true" class="MJX-TEX" aria-hidden="true" style="margin-left: 0px; margin-right: 0px;">
<mjx-mi class="mjx-i">
<mjx-c class="mjx-c1D465 TEX-I"></mjx-c>
</mjx-mi>
<mjx-mo class="mjx-n" space="4">
<mjx-c class="mjx-c3D"></mjx-c>
</mjx-mo>
<mjx-texatom space="4" texclass="ORD">
<mjx-mfrac>
<mjx-frac type="d">
<mjx-num>
<mjx-nstrut type="d"></mjx-nstrut>
<mjx-mrow>
<mjx-mo class="mjx-n">
<mjx-c class="mjx-c2212"></mjx-c>
</mjx-mo>
<mjx-mi class="mjx-i">
<mjx-c class="mjx-c1D44F TEX-I"></mjx-c>
</mjx-mi>
<mjx-mo class="mjx-n" space="3">
<mjx-c class="mjx-cB1"></mjx-c>
</mjx-mo>
<mjx-msqrt space="3">
<mjx-sqrt>
<mjx-surd>
<mjx-mo class="mjx-n">
<mjx-c class="mjx-c221A"></mjx-c>
</mjx-mo>
</mjx-surd>
<mjx-box style="padding-top: 0.087em;">
<mjx-maction title="descriminant">
<mjx-mrow>
<mjx-msup>
<mjx-mi class="mjx-i">
<mjx-c class="mjx-c1D44F TEX-I"></mjx-c>
</mjx-mi>
<mjx-script style="vertical-align: 0.289em;">
<mjx-mn class="mjx-n" size="s">
<mjx-c class="mjx-c32"></mjx-c>
</mjx-mn>
</mjx-script>
</mjx-msup>
<mjx-mo class="mjx-n" space="3">
<mjx-c class="mjx-c2212"></mjx-c>
</mjx-mo>
<mjx-mn class="mjx-n" space="3">
<mjx-c class="mjx-c34"></mjx-c>
</mjx-mn>
<mjx-mi class="mjx-i">
<mjx-c class="mjx-c1D44E TEX-I"></mjx-c>
</mjx-mi>
<mjx-mi class="mjx-i">
<mjx-c class="mjx-c1D450 TEX-I"></mjx-c>
</mjx-mi>
</mjx-mrow>
</mjx-maction>
</mjx-box>
</mjx-sqrt>
</mjx-msqrt>
</mjx-mrow>
</mjx-num>
<mjx-dbox>
<mjx-dtable>
<mjx-line type="d"></mjx-line>
<mjx-row>
<mjx-den>
<mjx-dstrut type="d"></mjx-dstrut>
<mjx-mrow>
<mjx-mn class="mjx-n">
<mjx-c class="mjx-c32"></mjx-c>
</mjx-mn>
<mjx-mi class="mjx-i">
<mjx-c class="mjx-c1D44E TEX-I"></mjx-c>
</mjx-mi>
</mjx-mrow>
</mjx-den>
</mjx-row>
</mjx-dtable>
</mjx-dbox>
</mjx-frac>
</mjx-mfrac>
</mjx-texatom>
<mjx-mo class="mjx-n">
<mjx-c class="mjx-c2E"></mjx-c>
</mjx-mo>
</mjx-math>
<mjx-assistive-mml unselectable="on" display="block">
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
<mi>x</mi>
<mo>=</mo>
<mrow data-mjx-texclass="ORD">
<mfrac>
<mrow>
<mo>−</mo>
<mi>b</mi>
<mo>±</mo>
<msqrt>
<maction actiontype="tooltip">
<mrow>
<msup>
<mi>b</mi>
<mn>2</mn>
</msup>
<mo>−</mo>
<mn>4</mn>
<mi>a</mi>
<mi>c</mi>
</mrow>
<mtext>descriminant</mtext>
</maction>
</msqrt>
</mrow>
<mrow>
<mn>2</mn>
<mi>a</mi>
</mrow>
</mfrac>
</mrow>
<mo>.</mo>
</math>
</mjx-assistive-mml>
</mjx-container>
</body>
まずは、インデント処理を自動でやってくれるサービスと出会うことから始めました。
いろいろなプログラムを自動整形するサービス
MathJaxを理解する作業をはじめて、いきなりありがたいサービスにまた出会う。このサービスのプログラムもすごいね。完璧すぎる自動整形インデント処理をしてくれます。そのJavaScriptの自動整形サイトが以下です。
- Online Javascript Beautifier - BeautifyConverter.com
他にもBeautifier Minifier/CSV/Excel/TSV/HTML/JSON/SQL/XML/YAML/Validators/CSS/Gen/Unit/Escape/IMG/PDF/IP/Color/Othersという整形処理ができる。自分で作ったプログラムが画期的である場合にはこのような自動整形処理を他人に任せるのは知的財産の流出の危険があるので、気を付けてください。信頼できるサイトもあるかもしれませんが、自分は知りません。サービス自体はありがたい。Microsoftがこういう機能をVisualStudioCodeにつけていたら楽だったのにな。あるっちゃあるんすよ。Shift+Alt+Fらしい。あまり自動整形されないっす。
とはいいつつも自動整形が必要なのはここまでヒドイと思ったプログラムだけですけどね。自分でプログラム作成して整形したものが最高に美しい。余計なことをするのがMicrosoftのエディタって感じですけど、Microsoftの考え方と共鳴しながらのコーディングをして、美しさを求めるのが自分流。MathJaxを自動整形して見えてくるものはある。最初の方に関数が連想配列でつめこまれて1000から3000くらいの関数が配列化されている。しかも番号だけで管理している。手ごわい。いみわからん。まったくいみわからん。変数名も1文字が多い。意味わからん。そんなことできるの?ってぐらいスゴイ。なんかそういう風にプログラムを意味わからんくする自動ツールがあるのかもしれん。でも自動整形したら少しましになった。あー、ありましたねminifyとかってサービスこれのことかな。意味のあるプログラム変数名を圧縮してしまう技。こういうのを使ってるのかもしれない。でもソースで配布してるのおかしくね。MathJaxの中の人。ちがうのか。謎のままおいておこう。
デバッグ環境を整える
基本的にはVScodeで簡易WebServerの元でデバッグで記述した方法によってVSCodeでデバッグします。ソースのダウンロードにはGitコマンドっていうのを使いたくて、Git for Windowsみたいなのをインストールしました。Gitのインストーラーがややこしい。Ver2.38.1ですが、CommandPromptでGitコマンドが使えりゃいいかなと思ったりするだけなんですけど、ややこしい。基本デフォルト設定でインストールするだけかなと思ったんですけどところどころ触ってやらないとCommandPromptで使えるような状態にはならないらしい。インストーラはhttps://gitforwindows.org/からデカデカとあるDownloadから入手。手を加えたところを太字にするとして、おおまかな流れは
実行→アプリがデバイスに変更[はい]→ライセンス確認[I Agree]→インストール先[Next]→フォルダ作成確認[はい]→
インストールオプション[Next](右クリックメニューにGitShell起動とGitBash起動を追加/大きいファイルサポート/*.gitファイルをテキストエディタで編集/*.shファイルをGitBashで起動)→スタートメニューのグループ名(GITのまま)[Next]→コミットメッセージで使うエディタは何[Use Vim(the ubiquitous text editor) as Git's default editor]-[Next]→Git initで作られるブランチ名(master (Let Git Decide:Gitに決定させよう))[Next]→パスの設定[Git from the command line and also from 3rd-party software(path追加Gitインストール先\Git\cmd)]-[Next]→OpenSSHのインストール[Use bundled OpenSSH]-[Next]→HTTPSリモートリポジトリ接続[Use the OpenSSL library]-[Next]→改行コード自動変換[Checkout Windows-style,commit Unix-style line endings(コミット処理でなんかうまくいかないときはこの設定が邪魔していることも覚えておかないといけませんよ。あまり使わない機能なので大丈夫だと思いますけど)]-[Next]→Git Bashターミナルを選択[Use MinTTY]-[Next]→Git pullの設定[Default(git pull --ff)]-[Next]→Credentioal設定[Git CredentialManager]-[Next]→オプション[Enable file system caching のみ ON]-[Next]→試験運用オプション[check無し]-[Install]
あらゆるプロジェクトにおいて、GitHubでソースコードを管理する波は来ています。確実に。Gitコマンドつかえるようになったほうが良いと思います。GitHubの一人勝ちだな。一般向けに最初に納得いくものを作った人たち偉い。会社には会社の中のコード管理があると思います。Visual Source Safeなつかしい。そんなのつかっているひといるのかな。ソース管理とかしたことないからわからないことばかりだけど、必要だよね。
例えばC:¥JavaScriptフォルダを作って、そこにソースをダウンロードする場合。
cd C:¥JavaScript
git clone git://github.com/mathjax/MathJax.git MathJax
これだけでC:¥JavaScript¥MathJaxが出来て、その中にes5フォルダが出来上がります。es5とはEcmaScriptというJavaScriptのもう一つの規格名がありまして、これにしたがっているのがes5です。何がどう違うかは自分は完全には理解していません。これに対応している関数や配列なんかには __esModule= true という値が取得できるようになっていたりします。高度なJavaScriptではこの値を制御するみたいな記事もあります。自分はまだ理解していません。
いろいろな種類の動作を確認するサンプルもダウンロードしましょう。MathJaxの多くの機能を網羅するようなSampleってのはありがたいものです。以下のアドレスから取得できます。
同じフォルダ(例C:\JavaScript\MathJax)にDownloadしましょう。結果的にC:\JavaScript\MathJax\MathJax-Example\MathJax-base\index.htmlのようなものにアクセスできるようになります。このindex.htmlには2次方程式の解の公式がサンプル表示されるようになっています。Mathjaxのプログラムの参照部分が ../MathJax.js になっているので、 ../../es5/tex-mml-chtml.js のように書き換える必要があります。全部のファイルで書き換えないとだめなのでちょっと辛いですけど、やってみましょう。ファイルによっては違うプログラムを参照した方がいいようなものもあります。これで関連記事のようなVSCodeを設定をするとデバッグができるようになります。
軽く追いかけてみる
序盤その1
自動整形で変換したtex-mml-chtml.jsの1行目の (function(){ にブレークポイントを設定して、プライマリサイドバーの上から4つめ実行とデバッグを選択して、launch.jsonを作ったら、Open index.html の横にある 蛍光色黄緑 ▷ のボタンを押します。ブラウザが起動して、VisualStudioCodeのtex-mml-chtml.jsの1行目で止まります。
最初の行に"use strict";とあるので、このプログラムでは、強制的に構文チェックをするモードになり、変数定義を正式に実施していないとエラーになるモードになります。
次に __webpack_modules__ 代入処理で配列が定義されます。 {351 : … とあるので、351が最初に定義される関数みたいですね。何に使うものなのか、この番号からはあまり想像つきません。ものすごい数の配列になってそう。__webpack_modules__はいわば、関数群ですね。
次に __webpack_module_cache__ = {}; という上記関数群のためのcacheと思われる変数への初期化がされます。プログラムが進むとここにいろいろ設定されていくのでしょう。よく使うやつとかがこんなかにはいるのかな。__webpack_modules__はものスゴイ数の関数がありますので。
次に function __webpack_require__(t){ … } があるので、tという変数の引数を受け取る__webpack_require__関数が定義されています。短いです。
function __webpack_require__(t) {
var e = __webpack_module_cache__[t];
if(void 0 !== e) return e.exports;
var r = __webpack_module_cache__[t] = {
exports: {}
};
return __webpack_modules__[t].call(r.exports, r, r.exports, __webpack_require__), r.exports
}
ペロッと貼っておきました。cacheの中に設定されている連想配列キー変数 t の配列値を e に取得して何もなければ t の配列値にexports : {} という連想配列を代入して、その値を更に r で覚えさせておくみたいだね。そして、最初に登場にした巨大な関数群を格納している配列 t を実行しています。 返却する値として .call は連想配列値を実行ですね。連想配列にプログラムを格納しておくという技なんだな。なるほど。その引数は、たった今、{exports:{}}とした r の exports キーの値 {} と r 全体 と また同じ、r の exports キーの値 {} と この関数全体の値 __webpack_require__ も引数にしていて4つが引数になっています。この関数群の中のひとつの実行結果が返り値の一つ目、そしてもうひとつ何回も登場するr の exports キーの値 {} を返却するみたい。
次に__webpack_require__に.gというメンバ変数をつくって、これに何やら設定する関数が実行されます。
__webpack_require__.g = function() {
if("object" == typeof globalThis) return globalThis;
try {
return this || new Function("return this")()
} catch(t) {
if("object" == typeof window) return window
}
}();
ここは単純だな。globalThisという値を __webpack_require__.g に代入する処理なんだけど、ちゃんとobjectとして存在しているかを確認して代入している慎重さがある。globalThisというオブジェクトが無い場合は例外処理付の次の処理を実施します。tryはエラーが発生する可能性がある処理で、エラーが発生したらcatchの処理をするという感じです。返却される可能性のある値は、this || new Function("return this")() エラーになった場合は、window ですね。とにかく取得できる環境変数は取るみたいな処理ですね。catch(t)のtはエラー情報格納変数です。eを使う人も多い印象だけど、tでもいいんだね。
勉強になるのは this || new Function("return this")() っていう部分が無駄に感じるけど、Debugしてみると単純なthisはundefinedで、new Function("return this")()だとwindowオブジェクトがかえってきたりして、意味が違うんだなって思ったことです。そして、この場合の || の使い方がむずい。なんじゃコレ。論理和演算だからどっちかがtrueになったらtrueが返却され、両方がfalseならfalseがかえるのだろう。それも動かないときはwindowオブジェクトで扱う。
まだわからないのは
- new Function("return this")()の後ろのカッコの有り無しの違い
- 関数構文の中のthisとfunction(){}の中のthisの違い。
また今度だな。
序盤その2
次にvar __webpack_exports__ = {}; で __webpack_exports__ の連想配列変数を初期化。
次はちょっと特殊 !function(){}という関数の実行処理です。戻り値のBool値が反転しそうだ。論理否定付きの関数。こんなこともできるんだな。なるほどなるほど。function xxx = {} や var xxx = { zzz : function(x,x,x) = {} }なら関数定義だけfunction(){ }なら実行する内容になるんだね。定義だけか関数だよといいながらも即実行。
次の部分からは __webpack_require__(t 【←数値】 )で5つの値 t, e, r, n, o を定義。なんの処理の関数を結び付けるのやら、みてもわからんだろうな。9515, 3282, 235, 265, 2388 暗号だな。さっきしらべたとおり __webpack_require__(t) を呼ぶと、__webpack_modules__[t].call(xx,xx,xx,xx)が実行される。__webpack_modules_cache__[t]には{ exports:{ } }が作成されている状態です。
他にも、undefinedで変数が沢山認識される。
_, _e, _n, _r, _t, _$, $r, $t, a, A, ae, Ae, an, ar, Ar, at, At, b, B, Be, bn, br, Br, bt, Bt, c, C, ce, Ce, cn, cr, Cr, ct, Ct, d, D, de, De, dn, dr, Dr, dt, Dt, e, E, ee, Ee, en, er, Er, et, Et, f, F, fe, Fe, fn, fr, Fr, ft, Ft, g, G, ge, Ge, gn, gr, Gr, gt, Gt, h, H, he, He, hn, hr, Hr, ht, Ht, i, I, ie, Ie, ir, Ir, it, It, j, J, je, Je, jr, Jr, jt, Jt, k, K, ke, Ke, kr, Kr, kt, Kt, l, L, le, Le, ln, lr, Lr, lt, Lt, m, M, me, Me, mn, mr, Mr, mt, Mt, n, N, ne, Ne, nn, nr, Nr, nt, Nt, o, O, oe, Oe, on, or, Or, ot, Ot, p, P, pe, Pe, pn, pr, Pr, pt, Pt, q, Q, qe, Qe, qr, Qr, qt, Qt, r, R, re, Re, rn, rr, Rr, rt, Rt, s, S, se, Se, sn, Sn, sr, Sr, st, St, t, T, te, Te, this, tn tr, Tr, tt, Tt, u, U, ue, Ue, un, ur, Ur, ut, Ut, v, V, ve, Ve, vn, vr, Vr, vt Vt, w, W, we, We, wr, Wr, wt, Wt, x, X, xe, Xe, xr, Xr, xt, Xt, y, Y, ye, Ye, yn, yr, Yr, yt, Yt, z, Z, ze, Ze, zr, Zr, zt, Zt
上記ぐらいが定義される。アルファベット全部の小文字(26)、大文字(26)と、アルファベット小文字or大文字に続いて[e,r,t]((26x2)x3=156) アルファベット小文字に続いて n (52)。n だけ大文字との組み合わせ変数が無い。意味深。全部使うのかな?この変数たち。
うち、Sn と i は使われていた。
Sn:Sn(t, e) {
(null == e || e > t.length) && (e = t.length);
for(var r = 0, n = new Array(e); r < e; r++)
n[r] = t[r];
return n
}
i:i(t, e) {
(null == e || e > t.length) && (e = t.length);
for(var r = 0, n = new Array(e); r < e; r++)
n[r] = t[r];
return n
}
だけ、定義済みでした。まったく同じ関数。
この関数が呼ばれるときの t は、
t:(30) ['[tex]/action', '[tex]/ams', '[tex]/amscd', '[tex]/bbox', '[tex]/boldsymbol', '[tex]/braket', '[tex]/bussproofs', '[tex]/cancel', '[tex]/centernot', '[tex]/color', '[tex]/colortbl', '[tex]/configmacros', '[tex]/enclose', '[tex]/extpfeil', '[tex]/html', '[tex]/mathtools', '[tex]/mhchem', '[tex]/newcommand', '[tex]/noerrors', '[tex]/noundefined', '[tex]/physics', '[tex]/require', '[tex]/setoptions', '[tex]/tagformat', '[tex]/textcomp', '[tex]/textmacros', '[tex]/unicode', '[tex]/verb', '[tex]/cases', '[tex]/empheq']
で、e は undefined だから e は t の配列の要素数(30)になります。n は 要素数30の配列になって、r が 0 から 29 まで変動して、n[r] = r[r]; なので配列のコピーですね。コピーした n を返します。
何やってるか、想像がつきそうなのが2個3個あればいいな。
__webpack_modules__[9515].call(r.exports, r, r.exports, __webpack_require__)
9515: function(t, e, r) {
var n = this && this.__values || function(t) {
var e = "function" == typeof Symbol && Symbol.iterator,
r = e && t[e],
n = 0;
if(r) return r.call(t);
if(t && "number" == typeof t.length) return {
next: function() {
return t && n >= t.length && (t = void 0), {
value: t && t[n++],
done: !t
}
}
};
throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.")
};
Object.defineProperty(e, "__esModule", {
value: !0
}), e.MathJax = e.combineWithMathJax = e.combineDefaults = e.combineConfig = e.isObject = void 0;
var o = r(3282);
function i(t) {
return "object" == typeof t && null !== t
}
function s(t, e) {
var r, o;
try {
for(var a = n(Object.keys(e)), l = a.next(); !l.done; l = a.next()) {
var c = l.value;
"__esModule" !== c && (!i(t[c]) || !i(e[c]) || e[c] instanceof Promise ? null !== e[c] && void 0 !== e[c] && (t[c] = e[c]) : s(t[c], e[c]))
}
} catch(t) {
r = {
error: t
}
} finally {
try {
l && !l.done && (o = a.return) && o.call(a)
} finally {
if(r) throw r.error
}
}
return t
}
e.isObject = i, e.combineConfig = s, e.combineDefaults = function t(e, r, o) {
var s, a;
e[r] || (e[r] = {}), e = e[r];
try {
for(var l = n(Object.keys(o)), c = l.next(); !c.done; c = l.next()) {
var u = c.value;
i(e[u]) && i(o[u]) ? t(e, u, o[u]) : null == e[u] && null != o[u] && (e[u] = o[u])
}
} catch(t) {
s = {
error: t
}
} finally {
try {
c && !c.done && (a = l.return) && a.call(l)
} finally {
if(s) throw s.error
}
}
return e
}, e.combineWithMathJax = function(t) {
return s(e.MathJax, t)
}, void 0 === r.g.MathJax && (r.g.MathJax = {}), r.g.MathJax.version || (r.g.MathJax = {
version: o.VERSION,
_: {},
config: r.g.MathJax
}), e.MathJax = r.g.MathJax
},
なかなかわけわからん。
var n = this && this.__values || function(t){…}
グローバルオブジェクトだからthisはWindowオブジェクトなんだけど、strictモードなので、. の前が省略されているので、undefined だね。だから、値だけを取り出す、this.__values も undefined。n は function(t) があるから true かな。論理演算している意味が謎だわ。何がしたいんだろう。ま、あとあと何回か呼び出されるんだろうと思って、ブレークポイントを設定したら、謎のコードが33回呼ばれる。おいかけきれるかこれ? t には何かのキーワードみたいなのが入って呼ばれるね。呼び出されるときの t の値を記録してみるか。
追記※1 : やっぱり論理演算にはJavaScript特有の動作がありました。論理和の場合は、左から0 や null や undefinedのような値が続いて、一番最初に左側に現れた値をそのまま返すんだそうな。なので、最初の値がオブジェクトや関数や変数ならばそのまま、その値が返るそうです。論理積の場合は左側に 1 や true がある場合は最初のオブジェクト値や関数や変数値がかえるそうなのです。
エグイ仕様だな。もう比較する必要ないね。みたいなサバサバ系の処理だ。これは専門家じゃないとむずいな。JavaScript末恐ろしい。自分なんかは知らないことだらけなんじゃね。と、思えてきた。深い!JavaScript。勉強しがいがある! 追記※1ここまで。
1回目 (10) ['paths', 'source', 'dependencies', 'provides', 'load', 'ready', 'failed', 'require', 'pathFilters', 'versionWarnings'] 2回目 ( 1) ['loader'] 3回目 ( 9) ['input', 'output', 'handler', 'adaptor', 'document', 'elements', 'typeset', 'ready', 'pageReady'] 4回目 ( 2) ['startup', 'options'] 5回目 ( 2) ['startup', 'options'] 6回目 (1) ['_'] 7回目 (1) ['components'] 8回目 (37) ['a11y/semantic-enrich', 'a11y/complexity', 'a11y/explorer', '[mml]/mml3', '[tex]/all-packages', '[tex]/action', '[tex]/autoload', '[tex]/ams', '[tex]/amscd', '[tex]/bbox', '[tex]/boldsymbol', '[tex]/braket', '[tex]/bussproofs', '[tex]/cancel', '[tex]/centernot', '[tex]/color', '[tex]/colorv2', '[tex]/colortbl', '[tex]/configmacros', '[tex]/enclose', '[tex]/extpfeil', '[tex]/html', '[tex]/mathtools', '[tex]/mhchem', '[tex]/newcommand', '[tex]/noerrors', '[tex]/noundefined', '[tex]/physics', '[tex]/require', '[tex]/setoptions', '[tex]/tagformat', '[tex]/textcomp', '[tex]/textmacros', '[tex]/unicode', '[tex]/verb', '[tex]/cases', '[tex]/empheq'] 9回目 (3) ['tex', 'mml', 'sre'] 10回目 (4) ['startup', 'input/tex', 'input/tex-full', '[tex]/all-packages'] 11回目 (4) ['[tex]/amsCd', '[tex]/colorV2', '[tex]/configMacros', '[tex]/tagFormat'] 12回目 (1) ['_'] 13回目 (6) ['adaptors', 'components', 'core', 'handlers', 'mathjax', 'util'] 14回目 (1) ['global'] 15回目 (1) ['_'] 16回目 (1) ['input'] 17回目 (1) ['_'] 18回目 (1) ['input'] 19回目 (2) ['mathml_ts', 'mathml'] 20回目 (1) ['_'] 21回目 (1) ['output'] 22回目 (1) ['checkReady'] 23回目 (1) ['_'] 24回目 (1) ['output'] 25回目 (2) ['chtml', 'common'] 26回目 (1) ['fonts'] 27回目 (1) ['fonts'] 28回目 (1) ['fontURL'] 29回目 (1) ['font'] 30回目 (1) ['_'] 31回目 (1) ['ui'] 32回目 (1) ['_'] 33回目 (1) ['a11y']
呼ばれるのは、この9515をコールしたときではなく、後で、違う方法で実行されるように呼ばれるようだ。そのときに、このような引数が渡されて実行される。でも、デバッガによると n には、この関数全体が格納される。おそらく n によってこの関数が実行されるんだろう。論理演算ってそういう解釈があるんだなとは疑問に思いつつも納得しようと思う。調べないとな。33回も呼ばれるんだから、後で、こんなのあったなぁってなるんだろう。先に進もう。
次に実行されるのはObject.defineProperty(e, "__esModule", { value: !0 })
で、Object.defineProperty()はオブジェクトの定義をする命令で、第一引数のオブジェクトに、第二引数のメンバ変数に第三引数を値として設定している。つまり、e.__esModule = {value : !0}
としている。なんで!0なんだろう。!0 って true のことだと思うので、e.__esModule = {value : true}
って感じだと思う。 __esModule は、EcmaScriptに準拠したモジュールかを設定しているとか説明があった。変数 e の扱いを決定するものだな。でも、e.__esModule = true
じゃなくて{value : true}
なんだな。
続けて、xxx = void 0;を設定という形式で
e.MathJax = undefined; e.combineWithMathJax = undefined; e.combineDefaults = undefined; e.combineConfig = undefined; e.isObject = undefined;
としている。e は、どうやら環境変数って意味っぽいな Environments の e だな。MathJax は、このプログラムの核となる設定でcombineは結合とか混合って意味でwithMathJaxはMathJaxと結合するもの。Defaults規定値で結合するもの。Configは設定で結合するもの、isObjectはオブジェクトかどうか。って感じかな。ひとつ感じるのは、まだ何も始まってすらいないという感じだな。これだけおおがかりなことやっていながら、設定するのは、undefined だもんな。
次は var o = r(3282);
が実行されます。rは関数が格納されていて、__webpack_require__です。いやはや、この__webpack_require__(9515)を通じて、__webpack_modules__[9515].call()がされて今にいたっているのに、それが終わるのを待たずして、関数の内で、また新しく__webpack_require__(3282)を実行するようなものですね。確か、この__webpack_require__(9515)の後も同じように__webpack_require__(3282)が実行される流れになっていたような。ここでも実行しようとするんだね。3282は関数の内容が少ない。
o = { VERSION: "3.2.2", __esModule : true } になる。でも、次に呼ばれる__webpack_require__(3282)の結果は e 配列に追加格納されるような。さっき環境変数の e にいくつかundefined値が設定されたものもあったな。そして o にも同じような値を持たせるんだな。今、結構1文字の変数埋まってきてるな。環境変数っぽい e 。今しがた論理演算で込みなのに取得された n 。そして、o 。それから__webpack_require__が格納された r 。9515のcall内での t は r.export r という引数で{ Exports : {} }に対応する。eは r.Exportsの{}に対応しているがeには値が設定されてExports値の中身が増えていくはず。呼ばれる前は t は配列番号の9515を保持するモノとして使われていた。
この後、さらに2つの1文字変数に関数が格納されます。
i 短い関数function i(t) { return "object" == typeof t && null !== t }
、そして s には割かし長めの関数がfunction s(t, e) { … }
。
そして今しがた獲得したiとsの関数をちょっと前に登場した環境変数に格納する。グローバル系の処理が多いね。これって、なんか違うjava Scriptを同時に動かしているsiteなら、変数が重複して動かなくなりそうなもんだけど大丈夫なのかな。
e.isObject = i; e.combineConfig = s;
に格納している。確かにe.isObject(t)は動かすと、t がオブジェクトなのかを識別して、オブジェクトなら1と返却するし、違うなら0になるね。combineConfig は長いよね。簡単にながめてみると。
関数 s は for文で 論理演算の元で格納された関数 n に引数 o を与えながら全ての o の要素分だけ繰り返す。o は Version と __esModuleだけだし、たいした繰り返し処理ではなさそうだ。それよか、この for 文がエグイ記述だな。
var a = n(Object.keys(e)), l = a.next(); !l.done; l = a.next()
ということなんだけど、初期値がカンマ区切りで2個設定されている l = a.next()
は次の値なのかな。繰り返し条件の !l.done
だから、l.done
が 0 の間は、!l.done
が 1 なので、繰り返す。l.done
が 1 なら終了で、増分は l= a.next
で次の配列値が l に入るみたいな感じだな。 ややこしい。e の配列には今は以下の通りになっていて、順番に実行されるのかな。
e.MathJax = undefined; e.combineWithMathJax = undefined; e.combineDefaults = undefined; e.combineConfig = s; e.isObject = i;
こんな感じの環境変数のキーを一個づつ a に取得 l には次の値。繰り返したい要素 2つの値を同時に処理できるというのは斬新だけどやりたい処理ってのは c には 次のキー値 l.value の値が入りつつ、論理演算で、__esModuleという文字列値でないときにtrueである且つ、e[c] instanceof Promise ? null !== e[c] && void 0 !== e[c] && (t[c] = e[c]) : s(t[c], e[c])
?instanceof Promise?ムズッ。Promiseってのは非同期・同期処理についてキャストできたかというのを判定する処理らしい。なんだよ非同期とか同期とか。関数によっては時間がかかるものとかは、順番に処理されることなく、次々と時間がかからない処理を進めていく。非同期。それを順番に処理するのは、同期処理。と言っていると思います。Promiseは処理をするタイミングを調整するものです。そういった関数であるかどうかを判定しているらしい。いづれにしても何がしたいのかわからない。論理演算だけをして、特に代入することもないという。わからん。e[c] instanceof Promiseの結果が true なら null !== e[c] && void 0 !== e[c] && (t[c] = e[c]) で false ならs(t[c], e[c])で、再帰処理がされる。いやそもそも i(t[c]) とか i(e[c]) とか t[c] とか e[c] とか なんだろうね。i(…) は引数がオブジェクトかどうかを判定する関数でした。cは、 MathJax/combineWithMathJax/combineDefaults/combineConfig/isObject/…esModule/で終了条件にesModuleというキーが使われている予感。他のものの場合は、それがオブジェクトなのかを判断するi(e[c])。t[c]。おいておくか。ちょろっとここにブレークポイントを設定してどういうものが実行されるかみてみてみましょう。
実行されるときには t の内容は以下のような値になっているようです。
{version: '3.2.2', _: {}, config: {paths: {mathjax: 'http://localhost:5500/es5'}, source: {}, dependencies: {}, provides: { }, load: Array(0), …}}
eは{loader: {versions: Map(0), ready: ƒ, load: ƒ, preLoad: ƒ, defaultReady: ƒ, …}}で、a = n(Object.key(e)) の a はn('loader')になります。nはちょっと前にあった関数が入っていて、
function(t /* ← 'loader' */) {
var e = "function" == typeof Symbol && Symbol.iterator,
r = e && t[e],/* e : Symbol(Symbol.iterator) && 'loader'[Symbol(Symbol.iterator)] → r : ƒ values() */
n = 0;
if(r) return r.call(t); /* r = function( t /='loader'=/ ){return t /='loader'=/ } → return 'loader' */
if(t && "number" == typeof t.length) return {
next: function() {
return t && n >= t.length && (t = void 0), {
value: t && t[n++],
done: !t
}
}
};
throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.")
}
でした。この t が'loader'ってことですね。 l は { value: "loader", done: false, } になります。for文の中身の
var a = n(Object.keys(e)), l = a.next(); !l.done; l = a.next()
この l です。a は {} です。Array Iterator と表現されます。このfor文の使い方は難しい。理解できない。lの中身がそうなる理由が見えてこない。初期値は長い関数によって帰ってくる値で n('loader') の結果が {} で、l = a.next() なんだけど、{ value: "loader", done: false, }っつうね。終了条件の l.done がどこからきたかはわかっていないけど、最初は false なので 1回は処理されるというね。で、おわるとl = a.next() が実行されて次の処理になる。
c = l.Value は最初は 'loader'
t[c] = undefined e[c] = {versions: Map(0), ready: ƒ, load: ƒ, preLoad: ƒ, defaultReady: ƒ, …} これは e['loader']の値です。 e[c] instanceof Promise : false
falseなので、再帰部分が呼ばれる。s(t[c], e[c])。ふむ。いずれにしても、ここでは論理式が書かれているだけで、処理はなにもされなくて、これがエラーにならないかどうかを確かめているだけなのだろう。何もなければ、t そのものが返却される。うまくいかないとエラーになる。
c はこの後 'loader' → 'versions' → 'ready' → 'load' → 'preLoad' → 'defaultReady' → 'getRoot' → 'pathFilter' → 'item' → '0' → 'item' → … になる。
こんな、調子だとわからないことだらけだな!
なんしか、e.combineDefaults = function t(e, r, o) { … } もおなじような試みの関数が設定される。
e.combineDefaults = t; また t が使われた。 e.combineConfig = s; e.isObject = i;
次に、e.combineWithMathJax = function(t) { return s(e.MathJax, t) }
が設定される。あ!!あー!これ今作ったばっかりの関数 s が呼ばれてる!でも、実行されるのはもっと後だな。でも引数は e.MathJax, t だ。s(t, e)だからな。でも、t が e.MathJax で、 e が t か。また t が引数。このときの t は {'loader' : {versions: Map(0), ready: ƒ, load: ƒ, preLoad: ƒ, defaultReady: ƒ, this : {} }}
みたいな値です。
void 0 === r.g.MathJax && (r.g.MathJax = {}),
r.g.MathJax.version || (
r.g.MathJax = {
version: o.VERSION,
_: {},
config: r.g.MathJax
}
),
e.MathJax = r.g.MathJax
あーそうか。呼び出される前に、var r =__webpack_module_cache__[t] = { exports: {} };処理やってるから2回目は、少なくともexportsの空の値に e 返す。っていう処理になるんだな。この後 3282 。で呼ばれても、同じ処理をするわけではないんだな。
__webpack_modules__[3282].call(r.exports, r, r.exports, __webpack_require__)
3282: function(t, e) {
Object.defineProperty(e, "__esModule", {
value: !0
}), e.VERSION = void 0, e.VERSION = "3.2.2"
},
9515の中のoに設定したのと同じ要領で、e に設定するのかと思いきや、知らぬ間に __webpack_module_cache__ に{ 3282 : Exports : { version : '3.2.2', __esModule : true }, 9515 : {isObject: ƒ, combineConfig: ƒ, combineDefaults: ƒ, combineWithMathJax: ƒ, MathJax: {…}, …} }ってのが出来上がってた。だから、3282は __webpack_module__[3282]は呼ばれず、__webpack_module_cache__[3282]のreturn で e.Exports = { version : '3.2.2', __esModule : true } が返却される。つまり実行済みだからもう一度やり直しにはならない。__webpack_module_cache__ は優秀な仕組み。9515でいろいろやっている内に設定されたのは自分の知能不足。__webpack_modules__のcallは、最初の一つ目の引数は呼ばれた関数のthisになるオブジェクトを指定している。その後に最大3つの引数が設定されていて、t = r, e = r.Exports, n = __webpack_require__ として処理されることは覚えておいてよいね。r に何が設定されているかで、処理が決まるといってもいい。そして、どこで r や r.Exports が変化するかを抑えないと駄目だ。このあたりがこのプログラムを理解するうえで重要そうだ。
__webpack_modules__[235].call(r.exports, r, r.exports, __webpack_require__)
235: function(t, e, r) {
var n, o, i = this && this.__values || function(t) {
var e = "function" == typeof Symbol && Symbol.iterator,
r = e && t[e],
n = 0;
if(r) return r.call(t);
if(t && "number" == typeof t.length) return {
next: function() {
return t && n >= t.length && (t = void 0), {
value: t && t[n++],
done: !t
}
}
};
throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.")
};
Object.defineProperty(e, "__esModule", {
value: !0
}), e.CONFIG = e.MathJax = e.Loader = e.PathFilters = e.PackageError = e.Package = void 0;
var s = r(9515),
a = r(265),
l = r(265);
Object.defineProperty(e, "Package", {
enumerable: !0,
get: function() {
return l.Package
}
}), Object.defineProperty(e, "PackageError", {
enumerable: !0,
get: function() {
return l.PackageError
}
});
var c, u = r(7525);
if(
e.PathFilters = {
source: function(t) {
return e.CONFIG.source.hasOwnProperty(t.name) && (t.name = e.CONFIG.source[t.name]), !0
},
normalize: function(t) {
var e = t.name;
return e.match(/^(?:[a-z]+:\/)?\/|[a-z]:\\|\[/i) || (t.name = "[mathjax]/" + e.replace(/^\.\//, "")), t.addExtension && !e.match(/\.[^\/]+$/) && (t.name += ".js"), !0
},
prefix: function(t) {
for(var r;
(r = t.name.match(/^\[([^\]]*)\]/)) &&
e.CONFIG.paths.hasOwnProperty(r[1]);
)
t.name = e.CONFIG.paths[r[1]] + t.name.substr(r[0].length);
return !0
}
},
function(t) {
var r = s.MathJax.version;
t.versions = new Map,
t.ready = function() {
for(var t, e, r = [], n = 0; n < arguments.length; n++) r[n] = arguments[n];
0 === r.length && (r = Array.from(a.Package.packages.keys()));
var o = [];
try {
for(var s = i(r), l = s.next(); !l.done; l = s.next()) {
var c = l.value,
u = a.Package.packages.get(c) || new a.Package(c, !0);
o.push(u.promise)
}
} catch(e) {
t = {
error: e
}
} finally {
try {
l && !l.done && (e = s.return) && e.call(s)
} finally {
if(t) throw t.error
}
}
return Promise.all(o)
},
t.load = function() {
for(var r, n, o = [], s = 0; s < arguments.length; s++)
o[s] = arguments[s];
if(0 === o.length)
return Promise.resolve();
var l = [],
c = function(r) {
var n = a.Package.packages.get(r);
n ||
(n = new a.Package(r)).provides(e.CONFIG.provides[r]),
n.checkNoLoad(),
l.push(n.promise.then(
(
function() {
e.CONFIG.versionWarnings &&
n.isLoaded &&
!t.versions.has(a.Package.resolvePath(r)) &&
console.warn("No version information available for component ".concat(r))
}
)
)
)
};
try {
for(var u = i(o), p = u.next(); !p.done; p = u.next()) {
var h = p.value;
c(h)
}
}
catch(t) {
r = { error: t }
}
finally {
try {
p && !p.done && (n = u.return) && n.call(u)
}
finally {
if(r)
throw r.error
}
}
return a.Package.loadAll(), Promise.all(l)
},
t.preLoad = function() {
for(var t, r, n = [], o = 0; o < arguments.length; o++)
n[o] = arguments[o];
try {
for(var s = i(n), l = s.next(); !l.done; l = s.next()) {
var c = l.value,
u = a.Package.packages.get(c);
u || (u = new a.Package(c, !0)).provides(e.CONFIG.provides[c]), u.loaded()
}
}
catch(e) {
t = { error: e }
}
finally {
try {
l && !l.done && (r = s.return) && r.call(s)
}
finally {
if(t)
throw t.error
}
}
},
t.defaultReady = function() {
void 0 !== e.MathJax.startup && e.MathJax.config.startup.ready()
},
t.getRoot = function() {
var t = "//../../es5";
if("undefined" != typeof document) {
var e = document.currentScript || document.getElementById("MathJax-script");
e && (t = e.src.replace(/\/[^\/]*$/, ""))
}
return t
},
t.checkVersion = function(n, o, i) {
return t.versions.set(a.Package.resolvePath(n), r),
!(!e.CONFIG.versionWarnings || o === r) && (console.warn("Component ".concat(n, " uses ").concat(o, " of MathJax; version in use is ").concat(r)), !0)
},
t.pathFilters = new u.FunctionList,
t.pathFilters.add(e.PathFilters.source, 0),
t.pathFilters.add(e.PathFilters.normalize, 10),
t.pathFilters.add(e.PathFilters.prefix, 20)
}
(c = e.Loader || (e.Loader = {})),
e.MathJax = s.MathJax,
void 0 === e.MathJax.loader /*だいぶ前のif文の比較演算子の対象。カンマ構文の最後*/
)
{ /* e.MathJax.loader が undefined のときの処理 */
( 0, s.combineDefaults )( /* s.combineDefaults メンバ関数の引数開始 */
e.MathJax.config,
"loader",
{
paths: {
mathjax: c.getRoot()
},
source: {},
dependencies: {},
provides: {},
load: [],
ready: c.defaultReady.bind(c),
failed: function(t) {
return console.log("MathJax(" . concat(t.package || "?", "): ") . concat(t.message))
},
require: null,
pathFilters: [],
versionWarnings: !0
}
),
(0, s.combineWithMathJax)( /* combineWithMathJax メンバ関数の引数開始 */
{
loader: c
}
); //長かったカンマ構文終わり。
try {
for(var p = i(e.MathJax.config.loader.pathFilters), h = p.next(); !h.done; h = p.next()) {
var f = h.value;
Array.isArray(f) ? c.pathFilters.add(f[0], f[1]) : c.pathFilters.add(f)
}
}
catch(t) {
n = { error: t }
}
finally {
try {
h && !h.done && (o = p.return) && o.call(p)
}
finally {
if(n)
throw n.error
}
}
}
e.CONFIG = e.MathJax.config.loader
},
ここでも9515とよく似た処理がされるね。t = r.Exports ⇔ {exports: {…}, undefined: undefined}, e = r ⇔ {}, r = r.Exports ⇔ ƒ __webpack_require__(t) { … } の3つの引数が使われる。引数の対応すら違っているな、__webpack_modules__[t].call(r.exports, r, r.exports, __webpack_require__)
ん?あ、callの処理を勘違いしているんだな。ちょっと調べてみる。おー。第一引数は呼び出した関数のthisとなるものらしい。nullとundefined(void 0)を設定すると、グローバルのthisになってWindowオブジェクトが返ってくるんだそうな。今回の場合はr.exportsがthisってことだな。なので、t = r ⇔ {exports: {…}, undefined: undefined}, e = r.exports ⇔ {}, r = __webpack_require__ ⇔ ƒ __webpack_require__(t) { … } ってことだ。おーちょっと解決。勘違い恐るべし。
t は this。e は Environments。r は result という意味かな? r.Exports を 格納する result。
以下のような値が設定されます。
e.CONFIG = undefined; e.MathJax = undefined; e.Loader = undefined; e.PathFilters = undefined; e.PackageError = undefined; e.Package = undefined;
そして、
var s = r(9515);{isObject: ƒ, combineConfig: ƒ, combineDefaults: ƒ, combineWithMathJax: ƒ, MathJax: {version: '3.2.2', _: {…}, config: {…}}} var a = r(265); {PackageError: ƒ, Package: ƒ, __esModule: true} var l = r(265); {PackageError: ƒ, Package: ƒ, __esModule: true}
の結果をs, a, l にそれぞれ格納。
r() で その時点で Exports されている値が取得できるんだね。
Object.defineProperty で e.Packageとe.PackageErrorに値と関数を設定。
{
enumerable : true
get : function() { return l.Package (※e.PackageErrorはl.PackageError) }
}
そして
var u = r(7525); {FunctionList: ƒ, __esModule: true}
の結果を u に格納。
次に無駄に長い if 文。カンマ区切り構文が続く、評価されるのは一番最後(右側)の値。e.PathFilters={source:function(t){},normalize:function(t){},prefix:function(t){}},…まだ続く。
まずはキー source からで e.CONFIG.source.hasOwnProperty(t.name) で t.name を作り、 t.name = e.CONFIG.source[t.name]を設定し、常に!0つまりtrueを返却するキー名sourceの値に結び付いた関数。
normalize は t.nameがパターンマッチで、/^(?:[a-z]+:\/)?\/|[a-z]:\\|\[/i つまり、先頭が(?:[a-z]+:\/)で始まるかを判定。例えばc:abcd:\やc:abcd:abcd:abcd:\みたいに:で始まって、aからzのアルファベットの連続があったあとに来て:\で閉じられるものもしくは、先頭からじゃなくても、aからzの1文字:\もしくは [ があるかを判定。i オプションなので大文字と小文字の区別をしないというマッチングになります。おそらくドライブ文字のようなものにマッチングしようとしていると推測されます。"[mathjax]/" + e.replace(/^\.\//, "") は、t.name の値として [mathjax]/を先頭に付け足して、最初の./を取っ払ったものに置換しています。末尾が ./**** に一致しなければ、.jsを付け足す。という処理をするようです。先に ./ があったら取っ払っていますので、拡張子が既につけられていないことを確認しているものですね。一行でやりたいことをまとめれるって素敵ですね。自分だったらもっと何段階かにわけないと駄目だな。で、見てみたんですけど、e は startup のとき t は { name: '[mathjax]/startup.js', original: 'startup', addExtension: true} となり、startup を [mathjax]/startup.js に置換・格納する処理になっています。
prefixはfor文の終了条件でパターンマッチングし [] の中が先頭から ] 以外の文字で最長マッチングした値を r[1] に取得。ようするに[]の中の文字列を r へ格納して、マッチングの結果 r[1] という名前のメンバがある限り繰り返し処理。r[0]には[xxxx]のように最長マッチングが取得できて、要するに r[0] は [] 付き、r[1] は [] 無しの文字列が取得できる。[] 無しの文字列をプログラム中では prefix プレフィックス:接頭辞と呼んでいるようで、その終わる部分の長さ以降からの文字を e.config.path['mathjax']の値、つまり http://localhosts:5500/es5 の後ろに startup.js 付け足す処理をします。
ふむー。具体的に何をするんだろうな。先頭から追っていくと、何に使われるかわからない関数の準備ばっかりになるんだろうか。すさまじいコード量だ。作った人すげー。日々、痛感させられる。自分は何かここまで頑張りとおしたことはあるだろうかと、過去への振り返りさえ発生する。見習いたいものだ。
とはいいつつも次の関数定義もざっと見ておく。
次の関数は割かし眺めだ。しかもやっぱりわけがわからない。こういうときは動かしてみてどうなるか見てみる。ひとついえるのは動かしてみてとはいうものの、この関数が呼ばれる保証はない。ただ、まだ前半なのプログラムの根幹をなす関数を定義している気がする。
動かすと t の値が {versions: Map(0) {size: 0}, ready: ƒ, load: ƒ, preLoad: ƒ, defaultReady: ƒ} こうなった。Version Map0とは?配列の便利なタイプがMapというものらしく、.set('xxx',{yyy:xxx,zzz:xxx}) や .get('xxx') や .has('xxx') といったメソッドや.size といったものがあります。Version番号くらいしか設定されないところに Map というのが不可解なくらいですね。あとは、動作した後に中々、多くの関数が定義されたなという印象。あとはカンマ構文は、セミコロンにできるだけ焼き直した方がデバッグしやすいけど、うかつに分解すると不具合が発生する元にもなるという諸刃の剣。でもちょっと分解しないとデバッグしておいかけにくい。自分みたいな素人が改造して使わないようにデバッグしにくいようにしてるんだろうなぁ。
さっそく、このあたりの定義されるだけの関数の中のプログラムにブレークポイントを設定してみました。一番最初に呼ばれたのは、t.getRoot の部分です。ふむ。なにげに気になっていた部分 //../../es5/とハードコーディングされているパスがあるが、MathJaxはどこにあるhtmlから呼ばれるかわからない構造のはずだし、このtex-mml-chtml.jsファイル自体からのパスだとしてもそんなところにはes5はない。おー。すぐに t は上書きされますね。 document.getElementById("MathJax-script") = null で e = document.currentScript で e.src は http://localhost:5500/es5/tex-mml-chtml.js になりました。そうすると。これの e.src.replace(/\/[^\/]*$/, "") は http://localhost:5500/es5/ です。/[/以外]末尾 で末尾の / から以外っていみで、後ろのファイル名が取り除かれた名前になります。t.getRoot に http://localhost:5500/es5/ がセットされます。 おー。やるなMathJax。
次に呼ばれたのは、t.preload です。o < Argument.length の間、繰り返します。Argument は 大きさ9の要素になっています。2つの連想配列があります。キーはcalleeとSymbol(Symbol.iterator)です。Arguments(9) ['loader', 'startup', 'core', 'input/tex', 'input/mml', 'output/chtml', 'output/chtml/fonts/tex.js', 'ui/menu', 'a11y/assistive-mml', callee: <accessor>, Symbol(Symbol.iterator): ƒ] で、繰り返し処理によってn[0]~n[8]の9個が Argument からコピーされます。
e.CONFIG =
{
paths : {mathjax: 'http://localhost:5500/es5'},
failed : { ƒ (t) {
\treturn console.log("MathJax(" . concat(t.package || "?", "): ") . concat(t.message))
}
},
source : {…},
dependencies : {…},
provides : {…},
load : Array(0),
versionWarnings : true
}
やっぱり、for文に.next()が使われるパターンの深い理解が必要だな。かなりの頻度で使われる。ふむhttps://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Generator/next によると、next()を使うと、value 実際に使いたい次々に取り出す配列値 と done 終了フラグ を返すそうな。終わったら true だそうです。
for(var arraydata = arrayobject, countobject = arraydata.next(); !countobject.done; countobject = arraydata.next()){ … ; var contentvalue= countobject.value; … }
for文はこの形式で構成されます。初期値の処理が二つになります。配列や連想配列構造のオブジェクトarrayobjectをarraydataに受け取り、この値に対してarraydata.next()を呼び出すたびに次の配列値へと移動しますが、最初の値の取り出しでもarraydata.next()が必要なので、実行して、実際に使う変数値として、countobject に保持させます。これがfor文の初期動作です。終了条件は、実際に使う値の countobject のメンバ関数 done(ダン) を監視すればよいことになります。最後の値を処理したら、true になります。なので、終了条件は !countobject.done となります。そして、次の値を実際に使用する変数 countobject に代入しつつも、arraydata.next() を呼び出せばいいです。for文の中では実際に使う値を、contentvalue = countobject.valueのように取り出すことをするでしょう。実際、mathjax でも、実にオーソドックスに配列の値を使ったfor文を処理しています。一方で、もうちょっと変わった連想配列の繰り返し処理中で特殊なfor文(for of:キー値のみ取り出し/for in:値の取り出し)は使っていないようです。for in だと関数内で追加で定義宣言(これをよくプロトタイプ関数と言っています。)した関数が配列の中の要素として使われるので、値が関数でないかを確認しなくてはいけなくなったりします。複雑なプログラムでは実は意外と使いにくいfor in。for of で配列値を指定した場合はキーではなく、配列値が使えます。for(var val 【of/in】 Array){…}
以上の事を踏まえると、t.ready と t.preLoad と t.defaultReady と t.getRoot と t.checkVersion と t.pathFileters関数が作られて、これがどこから何回呼ばれるのかを確認することで、大部分を把握できて、if(void 0 === e.mathJax.loader) が成立したとき、つまり e.MathJax.loader が undefined のときに s.combineDefaults と s.combineWithMathJax に複雑な引数が渡される処理を実施して、最後に、 i(e.MathJax.config.loader.pathFilters) の結果得られる要素全てについての処理を行う処理が実施されるので、この動きを見極めればよいことになる。
t.ready
このメンバ関数はsampleのような単純なhtmlからだと呼ばれない関数になっていた。なので、内容をおいかけるのはあとあとです。
t.Load
5万1000行目付近の r.CONFIG.load で、このt.Load は呼ばれます。呼ばれた時の argument 値は
{ "0": "input/tex-base", "1": "[tex]/newcommand", "2": "[tex]/action", "3": "output/chtml", }
となっていました。argument を一旦、 o[0] ~ o[3] にコピーします。
そして、o の要素数が 0 なら、return Promise.resolve(); を返して終了ですが、そのようなことはないので、もう少し処理が進みます。l = []; で空の配列と c = function(r){…}で関数を定義します。o 要素の値を h に取り込んで for文で繰り返し処理します。先ほど定義した c(h) がすぐに使われます。関数 c の中で r は h で o の要素値です。その r をつかった n = a.Package.pacakages.get(r); で n は
input/tex-base ⇔ n= { name : input/tex-base, isLoaded : true, isLoading : false, hasFailed : false, noLoad : true, dependencyCount : 0, dependencies (1) 0 : t { isLoaded: true, isLoading: false, hasFailed: false, dependencies: Array(1), dependents: Array(7), … } }, dependents : Array(7), canLoad : function() { /* noLoad true ⇒ return false */ return 0 === this.dependencyCount && !this.noLoad && !this.isLoading && !this.hasFailed }, promise : Promise {[[PromiseState]]: 'pending', [[PromiseResult]]: undefined}, provided : [], reject : function(){}, resolve : function(){}, } [tex]/newcommand ⇔ n = { name : [tex]/newcommand, isLoaded : true, isLoading : false, hasFailed : false, noLoad : true, dependencyCount : 0, … } [tex]/action ⇔ n = { name : [tex]/action, isLoaded : true, isLoading : false, hasFailed : false, noLoad : true, dependencyCount : 0, … } output/chtml ⇔ n = { name : output/chtml, isLoaded : true, isLoading : false, hasFailed : false, noLoad : true, dependencyCount : 0, … } }
となります。
関数 c では、こうして作られた4つのa.Package.pacakages.nameについて l.push という操作で Promise がスタックされるところが重要な処理になってるみたい。Promise が 具体的に何なのかを明確に理解していないのでわからないですが、大事なポイントなので後で整理するとしよう。
そして、finally で さきほど使った next() による for 文のときにつかった 一時的に配列をスキャンしてカウントしていく p.done がちゃんと true になったか確認して !p.done が false ならちゃんと処理したものとしてエラーを出さずに最後の return 処理をします。 ここで出てくるのが a.Package.loadAll() ですが、このloadALLはMathJaxで作られた関数です。以下のような内容。
function() {
var t, e;
try {
for(var r = i(this.packages.values()), n = r.next(); !n.done; n = r.next()) {
var o = n.value;
o.canLoad && o.load()
}
} catch(e) {
t = {
error: e
}
} finally {
try {
n && !n.done && (e = r.return) && e.call(r)
} finally {
if(t) throw t.error
}
}
}
this.packages.values() は、 以下のような値になっていました。
[[Entries]] { 0 : {"loader" => t}, 1 : {"core" => t}, 2 : {"startup" => t}, 3 : {"input/tex" => t}, 4 : {"input/tex-base" => t}, 5 : {"[tex]/ams" => t}, 6 : {"[tex]/newcommand" => t}, 7 : {"[tex]/noundefined" => t}, 8 : {"[tex]/require" => t}, 9 : {"[tex]/autoload" => t}, 10 : {"[tex]/configmacros" => t}, 11 : {"input/mml" => t}, 12 : {"output/chtml" => t}, 13 : {"output/chtml/fonts/tex.js" => t}, 14 : {"ui/menu" => t}, 15 : {"a11y/assistive-mml" => t}, 16 : {"[tex]/action" => t}, }
this.packages.values() の 要素 を n とすると、 n.value.name として得られるのが上記の値です。
この値って何だろうって考えたとき、 最初の
"0": "input/tex-base", "1": "[tex]/newcommand", "2": "[tex]/action", "3": "output/chtml",
から増えているので、chtml形式の出力のときに使われる、ファイル群なのではないかと思いました。なのでそういうファイルがes5ディレクトリの中にあるか確認をしてみました。すると
core.js ある! loader.js ある! startup.js ある! a11y/assistive-mml.js ある! input/mml.js ある! input/tex.js ある! input/tex-base.js ある! output/chtml.js ある! output/chtml/fonts/tex.js ある! ui/menu.js ある!
で[tex]というのが input/tex/extensions ならば
input/tex/extensions/action.js ある! input/tex/extensions/ams ある! input/tex/extensions/autoload ある! input/tex/extensions/configmacros ある! input/tex/extensions/newcommand ある! input/tex/extensions/noundefined ある! input/tex/extensions/require ある!
という関係なので、ファイル名を差してるんだろうね。てことはこのクソ長い5万行のプログラムに加えて、17の外部ファイルが、読み込まれる可能性がありそう。ということなので、すべてのファイルを自動整形して、1行目にブレークポイントを設定しておく必要がありそう。1行目が呼ばれるかどうかはわかないのだけど、とりあえずってことです。
そして、o.canLoad は 以下のような関数で
{ return 0 === this.dependencyCount && !this.noLoad && !this.isLoading && !this.hasFailed }
this.noLoad が true なので retrun は false になります。!this.noLoad ではじめて 0 になるので、この値が return の対象になります。先にも登場しましたが、念のため記述しておくと、JAVA Script 論理演算子と関数の代入式の併用に詳しい説明があります。
o.canLoad && o.load()
も同じ理屈で o.canLoad までが処理対象になります。ちなみに o.load は以下のような関数です。
function() {
if(!this.isLoaded && !this.isLoading && !this.noLoad) {
this.isLoading = !0;
var e = t.resolvePath(this.name);
l.CONFIG.require ? this.loadCustom(e) : this.loadScript(e)
}
}
今回は処理されない部分なので、こちらとしても深追いしません。走ったとしても noLoad のところで false なので if文の中の命令は処理されません。
んで、やっぱり、ちゃんとfor文の処理がされたかをfinalyの処理で確かめてますね。これは定石のように何回も登場する例外処理です。
t.preLoad
r.Loader.preLoad("loader"), r.Loader.load.apply(r.Loader, function(t) {…} 後ろから探した方が早いくらいのとこにあるこの部分で実行されます。
最初のfor文の中で使われる argument 引数は、以下のようなものです。
{ "0": "loader", "1": "startup", "2": "core", "3": "input/tex", "4": "input/mml", "5": "output/chtml", "6": "output/chtml/fonts/tex.js", "7": "ui/menu", "8": "a11y/assistive-mml", }
これはファイル群です。html 側で定義した Load ファイルは、'input/tex-base', '[tex]/newcommand', '[tex]/action', 'output/chtml'でしたが、それとは違う Load ファイルとなります。この 9 つの引数を n[o] の配列にコピー。この 9 つのファイル名について、for文で
u = a.Package.packages.get(c);
a.Package.packages に結び付いた ファイル名の Key に対応する値を取得し u に格納します。 u に何も結び付いていなければ、次の行の処理をします。基本的には、最初の呼び出しでは何も結び付いていないので、次の処理をするのが目的だと思います。u = new a.Package(c, !0)
を実行すると void 0 === r && (r = !1), this.isLoaded = !1, this.isLoading = !1, this.hasFailed = !1, this.dependents = [], this.dependencies = [], this.dependencyCount = 0, this.provided = [], this.name = e, this.noLoad = r, t.packages.set(e, this), this.promise = this.makePromise(this.makeDependencies())
という設定がなされて、name が ファイル名で、t(⇔a.Packages).pakeages.set(ファイル名)で、それ以外のメンバ変数が各種設定がされたような a.Package.Packeges.get(ファイル名) が構築されます。 因みに promise は非同期処理の順序処理に関する定義をするものです。これらのファイルの処理に関する非同期を制御する予定があるんだなと思っとけばいいかな。その制御をする makePromise メンバ関数と makeDependencies メンバ関数があります。
makePromise関数はこんな感じ。
function(t) {
var e = this,
r = new Promise(
(
function(t, r) {
e.resolve = t, e.reject = r
}
)
),
n = l.CONFIG[this.name] || {};
return n.ready &&
(
r = r.then(
(
function(t) {
return n.ready(e.name)
}
)
)
),
t.length &&
(
t.push(r),
r = Promise.all(t).then(
(
function(t) {
return t.join(", ")
}
)
)
),
n.failed &&
r.catch(
(
function(t) {
return n.failed(new c(t, e.name))
}
)
),
r /*カンマ演算子の最右値 return 対象*/
}
引数の最初 t は 次の処理を指定していて、第二引数が非同期処理が失敗した時の値のようですね。全部の処理が終わった時も t が次の処理になるようになっているように見えます。全部の処理が終わったかをみる場合の t は文字列っぽいですね。全部の名前文字列を , 区切りで結合して保持する処理があったりしています。l.CONFIG[ファイル名]の .ready というメンバ変数に呼び出し元オブジェクトで関数を入れておけば、それが、このPromiseを宣言した時点で実行されそうにも見えます。r は Promise の 結果であるオブジェクトが持たれていて、 PromiseStatus : Pending or Resolved or Rejected と PromiseResult undefined or 成功時の関数・変数 t のもしくは 失敗時の変数 r の呼び出しが保持されます。非同期処理中の成功・失敗はデバッグ処理でもたついたときにも発生するので、あまり長いことブレークしすぎないような工夫をしながら、デバッグする必要もありそうです。見る時は一か所でじっくり見て、次に進むときは再起動して次のポイントを見るとかね。
最初の呼び出しはファイル名 r = [tex]/action でした。
(n = new a.Package(r)).provides(e.CONFIG.provides[r])
Packageを定義しましたが、.provides では e.CONFIG.provides[r] が undefined なので、特に何もしませんでした。ふむ。
次にn.CheckNoLoad()が実行されます。以下のような関数です。
function() {
var t, e;
if(this.noLoad) {
this.noLoad = !1;
try {
for(var r = i(this.dependencies), n = r.next(); !n.done; n = r.next()) {
n.value.checkNoLoad()
}
} catch(e) {
t = {
error: e
}
} finally {
try {
n && !n.done && (e = r.return) && e.call(r)
} finally {
if(t) throw t.error
}
}
}
}
NoLoad は最初 true でしたが、反転します。そして、最初のファイル名についてのi(this.dependencies)の結果についても個別にCheckNoLoadを再帰して呼び出します。
i は下に示すような関数で ファイル名のオブジェクト this.dependencies {0: {isLoaded: true, isLoading: false, hasFailed: false, dependents: Array(7), dependencies: Array(1), …} } はこんな感じです。ずっとループする this.dependencies[0].dependencies[0].… とループする構造です。
function(t) {
var e = "function" == typeof Symbol && Symbol.iterator,
r = e && t[e],
n = 0;
if(r) return r.call(t);
if(t && "number" == typeof t.length) return {
next: function() {
return t && n >= t.length && (t = void 0), {
value: t && t[n++],
done: !t
}
}
};
throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.")
}
"function" == typeof Symbol は true なので、e = Symbol.iterator で、 r = e と同じ結果により if(r)が true で r.call(t) が return 対象で、{isLoaded: true, isLoading: false, hasFailed: false, dependents: Array(7), dependencies: Array(1), …} が 返却されます。noLoad はないので n.valuse.CheckNoLoad() は 最初のif文でfalseなので、なにも帰さないです。再帰から脱出です。
そして l.push(n.Promise.then(…)) によって非同期処理の完了後処理がスタックされていきます。
o = ['input/tex-base', '[tex]/newcommand', '[tex]/action', 'output/chtml']
で、繰り返して処理をします。
最後にreturn a.Package.loadAll(), Promise.all(l)
で
LoadAll()は以下のような関数を実行します。
function() {
var t, e;
try {
for(var r = i(this.packages.values()), n = r.next(); !n.done; n = r.next()) {
var o = n.value;
o.canLoad && o.load()
}
} catch(e) {
t = {
error: e
}
} finally {
try {
n && !n.done && (e = r.return) && e.call(r)
} finally {
if(t) throw t.error
}
}
}
各ファイル名のオブジェクトについて、o.canload が true なら load() を実行していく感じですね。ファイルをロードするのにものすごく非同期処理の順序を気にしている感じがします。確実に全部読み込んでから実行するためなのでしょう。エラーは絶対に出さないという強い意志を感じる凄みがあります。
t.defaultReady
void 0 !== e.MathJax.startup && e.MathJax.config.startup.ready()
の一行の処理で、e.MathJax.startup は定義されていれば、void 0 !== e.MathJax.startup が true で、定義されていたら、e.MathJax.config.startup.ready() を実行するというのが全て。呼ばれるのは、最後から4行目あたりのreturn r.CONFIG.ready()で呼ばれる。
e.MathJax.config.startup.ready()
e.MathJax.config.startup.ready() は、以下のような関数。
{
f(),
d(),
t.pagePromise.then(
(
function() {
return e.CONFIG.pageReady()
}
)
).then(
(
function() {
return t.promiseResolve()
}
)
).catch(
(
function(e) {
return t.promiseReject(e)
}
)
)
}
e.MathJax.config.startup.ready() { f() }
f() は、
a = new e.MathJax._.core.MmlTree.SerializedMmlVisitor.SerializedMmlVisitor,
l = e.MathJax._.mathjax.mathjax,
t.input = v(),
t.output = _(),
t.adaptor = S(),
t.handler && l.handlers.unregister(t.handler),
t.handler = M(),
t.handler && (l.handlers.register(t.handler),
t.document = O())
一行だからってなめてたけど、めっちゃ処理されるじゃん。深い!a = { NodeHandlers : Map(5){size: 5, inferredMrow => ƒ (t, e), annotation => ƒ (t, e), TeXAtom => ƒ (t, e), text => ƒ (t, e), XML => ƒ (t, e)}
e.MathJax._.core.MmlTree.SerializedMmlVisitor.SerializedMmlVisitor は、こんな関数
e.MathJax._.core.MmlTree.SerializedMmlVisitor.SerializedMmlVisitor = function r() {
return null !== t && t.apply(this, arguments) || this
}
この時の t は
t = function e(e){
return
void 0 === e && (e = null),
e || (e = new i.MmlFactory),
t.call(this, e) || this
}
で、e は undefined で、返却される値は t.call(this, e) || this で、e が いったん null値になった後、e = new i.MmlFactory
で function e() { return null !== t && t.apply(this, arguments) || this }
がその内容になっています。
e { defaultKind: 'unknown', nodeMap: Map(42) {size: 42, math => function e() { return null !== t && t.apply(this, arguments) || this } mi => ƒ e(), mn => ƒ e(), mo => ƒ e(), mtext => ƒ e(), mspace ms => ƒ e(), mrow => ƒ e(), inferredMrow => ƒ e(), mfrac => ƒ e(), msqrt => ƒ e(), mroot => ƒ e(), mstyle => ƒ e(), merror => ƒ e(), mpadded => ƒ e(), mphantom => ƒ e(), mfenced => ƒ e(), menclose => ƒ e(), maction => ƒ e(), msub => ƒ e(), msup => ƒ e(), musubsup => ƒ e(), munder => ƒ e(), mover => ƒ e(), munderover => ƒ e(), mmultiscripts => ƒ e(), mprescript => ƒ e(), none => ƒ e(), mtable => ƒ e(), mlabeledtr => ƒ e(), mtr => ƒ e(), mtd => ƒ e(), maligngtoup => ƒ e(), malignmark => ƒ e(), mglyph => ƒ e(), semantics => ƒ e(), annotation => ƒ e(), annotation-xml => ƒ e(), TexAtom => ƒ e(), MathChoice => ƒ e(), text => ƒ e(), XML => ƒ e(), } node: { annotation : ƒ { for(var t = [], e = 0; e < arguments.length; e++) t[e] = arguments[e]; return new( i.bind.apply( i, o( [void 0, r], n(t), !1 ) ) ) }, annotation-xml : ƒ, inferredMrow : ƒ, maction : ƒ, maligngroup : ƒ, malignmark : ƒ, math : ƒ, MathChoice : ƒ, menclose : ƒ, merror : ƒ, mfenced : ƒ, mfrac : ƒ, mglyph : ƒ, mi : ƒ, mlabeledtr : ƒ, mmultiscripts : ƒ, mn : ƒ, mo : ƒ, mover : ƒ, mpadded : ƒ, mphantom : ƒ, mprescripts : ƒ, mroot : ƒ, mrow : ƒ, ms : ƒ, mspace : ƒ, msqrt : ƒ, mstyle : ƒ, msub : ƒ, msubsup : ƒ, msup : ƒ, mtable : ƒ, mtd : ƒ, mtext : ƒ, mtr : ƒ, munder : ƒ, munderover : ƒ, mnone : ƒ, semantics : ƒ, TeXAtom : ƒ, text : ƒ, XLM : ƒ, math: ƒ, mi: ƒ, mn: ƒ, mo: ƒ, mtext: ƒ, …} }
となってから、t.call(this, e) || this が 呼び出される。
t は、以下のような関数です。
ƒ t(e) {
var r, o;
this.nodeHandlers = new Map;
try {
for(var i = n(e.getKinds()), s = i.next(); !s.done; s = i.next()) {
var a = s.value,
l = this[t.methodName(a)];
l && this.nodeHandlers.set(a, l)
}
} catch(t) {
r = {
error: t
}
} finally {
try {
s && !s.done && (o = i.return) && o.call(i)
} finally {
if(r) throw r.error
}
}
}
s.value は Mathから始まる値で a に代入される。"visit" + (t.charAt(0).toUpperCase() + t.substr(1)).replace(/[^a-z0-9_]/gi, "_") + "Node"
が返されて、t.methodName(a) は visitMathNodeが返ってくる。そのような名前の配列がthisに無いので undefined になることが多い。Mathの部分が一文字が大文字になったものと残りの文字をくっつける。その結果でも先頭文字が数字だったり小文字だったり_だったりしたら_に置き換える。という処理をする。ふむ。this.nodeHandlers.set で元の a の値と 変換された結果得られる this.['visitXxxxxNode'] が undefined だろうと 何かあったろうと ついにして set に設定する。残りの命令は例によって、for文が最後まで処理できたかを確認している。そうやってできたオブジェクト t を返却として準備する。
そして、l = {version: '3.2.2', handlers: e, document: ƒ (t, r) {return e.mathjax.handlers.document(t, r)}
, handleRetriesFor: ƒ (t) {return new Promise((function e(r, n) {try {r(t())} catch(t) {t.retry && t.retry instanceof Promise ? t.retry.then((function() {return e(r, n)})).catch((function(t) {return n(t)})) : t.restart && t.restart.isCallback ? MathJax.Callback.After((function() {return e(r, n)}), t.restart) : n(t)}}))}
, retryAfter: ƒ (t) {var e = new Error("MathJax retry");throw e.retry = t, }
, asyncLoad :ƒ (t) {return MathJax.loader.load(t)}
, handlers : { item: [] }} 次に t.input の関数 v()は…とその前に…
まだf() の最初の2行しか追えてない。残り7行あるし、d()も、その次も残ってる。ナゲー。preLoad やばい。
t.input = v(), t.output = _(), t.adaptor = S(), t.handler && l.handlers.unregister(t.handler), t.handler = M(), t.handler && (l.handlers.register(t.handler), t.document = O())
困ったね。
e.MathJax.config.startup.ready() { v() }
それで v()なんだけども
function v() {
var r, n, i = [];
try {
for(var s = o(e.CONFIG.input), a = s.next(); !a.done; a = s.next()) {
var l = a.value,
c = t.constructors[l];
if(!c) throw Error('Input Jax "' + l + '" is not defined (has it been loaded?)');
i.push(new c(e.MathJax.config[l]))
}
} catch(t) {
r = {
error: t
}
} finally {
try {
a && !a.done && (n = s.return) && n.call(s)
} finally {
if(r) throw r.error
}
}
return i
}
e.CONFIG.input = ['tex', 'mml'] で o() は iterator を返す関数(繰り返し処理する要素をまとめるもの)なので、結局次のように処理されます。 i.push(new c(e.MathJax.config['tex'])) → i.push(new c(e.MathJax.config['mml'])) このようにして呼ばれる c は、以下のような関数です。i.push(new c(e.MathJax.config['mml'])) は html側で定義していないので何も情報がないので、大した処理はされないはずです。
e.MathJax.config.startup.ready() { f() > c }
c = function(r) {
void 0 === r && (r = {});
var n = this,
o = s(
(
0,
c.separateOptions
)
(
r,
e.OPTIONS,
u.FindTeX.OPTIONS
),
3
),
i = o[0],
a = o[1],
l = o[2];
(
n = t.call(this, a) ||
this
).findTeX = n.options.FindTeX ||
new u.FindTeX(l);
var h = n.options.packages,
f = n.configuration = e.configure(h),
d = n._parseOptions = new m.default(f, [n.options, y.TagsFactory.OPTIONS]);
return
(
0,
c.userOptions
)
(
d.options,
i
),
f.config(n),
e.tags(d, f),
n.postFilters.add(p.default.cleanSubSup, -6),
n.postFilters.add(p.default.setInherited, -5),
n.postFilters.add(p.default.moveLimits, -4),
n.postFilters.add(p.default.cleanStretchy, -3),
n.postFilters.add(p.default.cleanAttributes, -2),
n.postFilters.add(p.default.combineRelations, -1),
}
なげー。プログラムだらけだな。これを c として、引数に e.MathJax.config[l] を迎え、 i.push(new c(e.MathJax.config['tex'])) → i.push(new c(e.MathJax.config['mml']))のように順番に i にプッシュされてスタックを作る。e.MathJax.config['tex']には inline のキーワード が格納されている。よく使われるのは $$ , $$とか \( , \) とかですね。inlineMath packages とか身近なキーワードうれしい。この命令は html で 設定した config の tex や mml を取得する部分なんだろうなって思う。だけど上のプログラムの引数 r がそうなんだけど inline とか packages がまだないね。淋しい。あー packages あるわ。n.option.packages ね。ってことは 今回は mml は定義してないから何もしない感じだな。
これが u.FindTeX.OPTIONS の値。 デフォルトの tex の option 値 っぽいのが設定されている。おー知ってるのまた出てきた。
{
inlineMath: [
["\\(", "\\)",],
],
displayMath: [
["$$", "$$", ],
["\\[", "\\]",],
],
processEscapes: true,
processEnvironments: true,
processRefs: true,
}
e.MathJax.config.startup.ready() { f() > c > separateOptions}
以下が、c.separateOptions関数。
c.separateOptions = function(t) {
for(var e, n, o, i, s = [], a = 1; a < arguments.length; a++)
s[a - 1] = arguments[a];
var l = [];
try {
for(var c = r(s), u = c.next(); !u.done; u = c.next()) {
var p = u.value,
h = {},
f = {};
try {
for(var d = (o = void 0, r(Object.keys(t || {}))), m = d.next(); !m.done; m = d.next()) {
var y = m.value;
(void 0 === p[y] ? f : h)[y] = t[y]
}
} catch(t) {
o = {
error: t
}
} finally {
try {
m && !m.done && (i = d.return) && i.call(d)
} finally {
if(o) throw o.error
}
}
l.push(h), t = f
}
} catch(t) {
e = {
error: t
}
} finally {
try {
u && !u.done && (n = c.return) && n.call(c)
} finally {
if(e) throw e.error
}
}
return l.unshift(t), l
}
あーなるほど。なるほど、動かしてみると引数が3つあった意味が分かった。全部使われるんだね。関数名の横の引数名をあたえるところが一つしかなくても、変数に格納されないだけで argument という特別な変数には、全部の引数が配列に格納されてました。こういう方法もあるんだな。t はユーザが設定した引数。 s[0] に第二引数、s[1] に第三引数が格納される感じで使う。なぜこうやってねじるようなことをするのかはわからない。
u.value はすでに、こういった設定情報をすでに保持している変数で、p にそのまま格納しているが、その結果、p の中身は以下のようになっています。
{ FindTeX: null, packages: ["base",], digits: {}, maxBuffer: 5120, formatError: function(t, e) { return t.formatError(e) }, }
という具合で packages メンバはあるが inlineMath は無い状態。
Object.keys(t || {}) = ['inlineMath', 'packages'] はユーザが指定したオプションです。このkeyと u の値のキーと一致するものがあるかないかを2項演算子で比較して あれば ? の後ろの f[y] = t[y] なければ h[y] = t[y] となります。h[y] には一致しない属性が集まります。f[y] には一致した属性があつまります。 全てを処理したら、l.push(h) で新しい属性を lにプッシュします。, 重複したキーの値は t = f で t に格納します。 最後に関数はスタックした l から t を 取り除いて、l を 返却します。
したがって、最初の2項演算子「 A ? true_instruction : false_instruction」は false で、h[y] = t[y] になります。h も f も最初は空の配列なので、h[y] が tex のときの値、 f[y] が packages のときの値になります。
h[y] = { inlineMath: [ [ "$", "$", ], ["\\(", "\\)",],], }
f[y] = { packages: [ "base", "newcommand", "action", ], }
となります。この後 l.push(h) で h の inlineMath の設定情報が l に保持されます。t にも f の内容がコピーされます。そして、全ての繰り返し処理をした後 return l.unshift(t), l
でlの配列の先頭にtが挿入されますが、2回目の処理のときに t は {} になっています。そして2回目で packages が l に追加でスタックされます。ので、[{ … },{packages : ['base', 'newcommand', 'action']}, {inlineMath :{ … : [ … ]} }, ]という状態になります。
e.MathJax.config.startup.ready() { f() > c > s()}
その後、関数が呼ばれる s は以下のようなモノ。
s = function(t, e) {
var r = "function" == typeof Symbol && t[Symbol.iterator];
if(!r) return t;
var n, o, i = r.call(t),
s = [];
try {
for(;
(void 0 === e || e-- > 0) && !(n = i.next()).done;) s.push(n.value)
} catch(t) {
o = {
error: t
}
} finally {
try {
n && !n.done && (r = i.return) && r.call(i)
} finally {
if(o) throw o.error
}
}
return s
}
s の呼び出しの第一引数が複雑な表記になっている。第二は 3 だけ。短っ。 でも引数は[{ … },{packages : ['base', 'newcommand', 'action']}, {inlineMath :{ … : [ … ]} }, ]です。 r は 値がある状態なので、!r 非成立。次に進みます。そして、第一引数のそのものである i で繰り返し処理をすると s に[{ … },{packages : ['base', 'newcommand', 'action']}, {inlineMath :{ … : [ … ]} }, ]がコピーされる感じになります。戻り値でもあるので、だいぶん前の c の関数の中の o にもコピーされます。この処理を全体的にみると s の配列の1番目は空{} 2番目は inlineMath 以外の値、 3番目は packages 以外の値が格納されます。
第一引数の手前のカッコの一番右がカンマ構文では有効な値で、 c.separateOptions は関数で、その後ろのカッコが引数になっていると思われる。ここでもまたカンマ構文があるがここは引数なので、カンマ左の一つ目が採用される。なので自分で設定した r が使われる。 r が設定されていなかったら2つめ、3つめが使われるんだっけか。この表記の意味がわかんねぇ。調べよっか。
i = 空{}、a = inlineMath 以外の値、l = packages 以外の値が格納されます。t.call(this, a)では、aはHTMLで指定したpackages : ['base', 'newcommand', 'action'] です。t はこんな関数。
function t(t) {
void 0 === t && (t = {}), this.adaptor = null, this.mmlFactory = null;
var e = this.constructor;
this.options = (0, n.userOptions)((0, n.defaultOptions)({}, e.OPTIONS), t),
this.preFilters = new o.FunctionList,
this.postFilters = new o.FunctionList
}
最初の2行ではthisがundefinedなので、何もせず、メンバ変数が作られるだけです。3行目は 関数の引数に関数が使われている感じで n.userOptions( (n.defaultOptions({}, e.Options)), t) ですから n.defaultOptions({}, e.Options)が算出されます。引数の e.Options は 以下の値 です。
{ FindTeX: null, packages: Array(1), digits: /^(?:[0-9]+(?:\\{,\\}[0-9]{3})*(?:\\.[0-9]*)?|\\.[0-9]+)/, maxBuffer: 5120, formatError: ƒ }
n.defaultOptions = function(t) {
for(var e = [], r = 1; r < arguments.length; r++)
e[r - 1] = arguments[r];
return e.forEach(
(
function(e) {
return p(t, e, !1)
}
)
), t
}
このときの e.Options = t は
{ parseAs : 'html', forceReparse : false, FindMathML : null, MathMLCompile : null, } というような値です。
ここでも関数名の横の引数が t だけと少なく arguments で全ての引数を処理しています。引数を e で格納して、return で t を返却します。 t を返却する前に p に {}, e (=e.OPTIONS), false という引数を渡した処理をします。
p は以下のような関数です。
function p(t, i, l) {
var h, f;
void 0 === l && (l = !0);
/* Define d Function */
var d = function(r) {
if(l && void 0 === t[r] && t.constructor !== a)
return "symbol" == typeof r &&
(r = r.toString()), e.OPTIONS.optionError('Invalid option "'.concat(r, '" (no default value).'), r),
"continue";
var h = i[r],
f = t[r];
if(!s(h) || null === f || "object" != typeof f && "function" != typeof f)
Array.isArray(h) ? (t[r] = [], p(t[r], h, !1)) : s(h) ? t[r] = u(h) : t[r] = h;
else {
var d = c(h);
Array.isArray(f) &&
(
1 === d.length &&
(d[0] === e.APPEND || d[0] === e.REMOVE) &&
Array.isArray(h[d[0]]) || 2 === d.length &&
d.sort().join(",") === e.APPEND + "," + e.REMOVE &&
Array.isArray(h[e.APPEND]) &&
Array.isArray(h[e.REMOVE])
)?
(h[e.REMOVE] &&
(f = t[r] = f.filter
((function(t) {
return h[e.REMOVE].indexOf(t) < 0
})
)
),
h[e.APPEND] && (t[r] = o(o([], n(f), !1),
n(h[e.APPEND]), !1)))
:
p(f, h, l)
}
};
/* Define d Function End*/
try {
for(var m = r(c(i)), y = m.next(); !y.done; y = m.next()) {
d(y.value)
}
} catch(t) {
h = {
error: t
}
} finally {
try {
y && !y.done && (f = m.return) && f.call(m)
} finally {
if(h) throw h.error
}
}
return t
}
この関数を実行したあとのe.forEachの関数の引数には
0 : { unknownFamily: "serif", fontURL: "js/output/chtml/fonts/tex-woff-v2", }, 1 : { unknownFamily: "serif", fontURL: "js/output/chtml/fonts/tex-woff-v2", }
となります。そして t を返す。
c = function(t){
return t ? Object.keys(t).concat(Object.getOwnPropertySymbols(t)) : []
}
で pacakges : ['base', 'newcommand', 'action'] の配列が返却。
r = function() {
var e = "function" == typeof Symbol && Symbol.iterator,
r = e && t[e],
n = 0;
if(r) return r.call(t);
if(t && "number" == typeof t.length) return {
next: function() {
return t && n >= t.length && (t = void 0), {
value: t && t[n++],
done: !t
}
}
};
throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.")
}
上記関数で r は空の関数で それに t = pacakges : ['base', 'newcommand', 'action'] を引数にしても以下のような値です。
{
value: pacakges, done: true,
} t は ['base','newcomamand', 'action']です。
下記のようなところからpreLoadは呼ばれているようです。
r.Loader.preLoad(
"input/tex-base", "[tex]/ams", "[tex]/newcommand", "[tex]/noundefined", "[tex]/require", "[tex]/autoload", "[tex]/configmacros"),
function() { var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], e = !(arguments.length > 1 && void 0 !== arguments[1]) || arguments[1]; if(MathJax.startup) { e && (MathJax.startup.registerConstructor("tex", MathJax._.input.tex_ts.TeX), MathJax.startup.useInput("tex") ), MathJax.config.tex || (MathJax.config.tex = {}); var r = MathJax.config.tex.packages; MathJax.config.tex.packages = t, r && (0, xt.insert)(MathJax.config.tex, { packages: r }) } } (["base", "ams", "newcommand", "noundefined", "require", "autoload", "configmacros"]);
e.userOptions = function(t) {
for(var e = [], r = 1; r < arguments.length; r++)
e[r - 1] = arguments[r];
return e.forEach(
(function(e) {
return p(t, e, !0)
})
), t
}
e.MathJax.config.startup.ready() { f() > c > defaltOption() > p()}
function p(t, i, l) {
var h, f;
void 0 === l && (l = !0);
/* define function */
var d = function(r) {
if(l && void 0 === t[r] && t.constructor !== a) {
return "symbol" == typeof r && (r = r.toString()),
e.OPTIONS.optionError('Invalid option "'.concat(r, '" (no default value).'), r),
"continue";
}
var h = i[r],
f = t[r];
if(!s(h) || null === f || "object" != typeof f && "function" != typeof f) {
Array.isArray(h) ?
(t[r] = [], p(t[r], h, !1))
:
s(h) ?
t[r] = u(h)
:
t[r] = h;
}
else {
var d = c(h);
Array.isArray(f) &&
(1 === d.length && (d[0] === e.APPEND || d[0] === e.REMOVE) &&
Array.isArray(h[d[0]]) ||
2 === d.length &&
d.sort().join(",") ===
e.APPEND + "," + e.REMOVE && Array.isArray(h[e.APPEND]) &&
Array.isArray(h[e.REMOVE])) ?
(h[e.REMOVE] &&
(f = t[r] = f.filter((function(t) {
return h[e.REMOVE].indexOf(t) < 0
}))), h[e.APPEND] && (t[r] = o(o([], n(f), !1), n(h[e.APPEND]), !1))) : p(f, h, l)
}
};
/* define function end */
try {
for(var m = r(c(i)), y = m.next(); !y.done; y = m.next()) {
d(y.value)
}
} catch(t) {
h = {
error: t
}
} finally {
try {
y && !y.done && (f = m.return) && f.call(m)
} finally {
if(h) throw h.error
}
}
return t
}
この関数を実行すると l は true になります。そして関数を定義だけして try まで飛びます。中身はあとで読むことになるでしょう。後ですぐ呼ばれます。
r(c(i))で得られる繰り返し要素について処理します。最初は {value: 'FindTeX', done: false} です。次が {value: 'packages', done: false} … という具合です。そうして d(y.value)のようにして、d('FindTeX') → d('packages') → d('digits') → d('maxBuffer') → d('formatError') → という処理が呼ばれます。こうした処理の末に出来上がる t が返却される予定です。 d() の内容を確認します。
void 0 === t[r] が true になりますので 、t[r] は undefined が返される値です。最初の段階で t が {} なので t['FindeTex'] もないので、undefined になるのでしょう。そして、t.constructer は空のオブジェクトで a が空の関数で不一致するので、trueになります。結果全てが true の if の成立処理が実行されます。"symbol" == typeof r の r は 'FindTex' で "string" ですから、false です。 symbol以外のような文字列ならば、文字列に変換して r へ格納する処理は行われません。
e.OPTIONS.optionError('Invalid option "'.concat(r, '" (no default value).'), r)のような設定をしたら、この if 文は "continue" という文字列を返却します。h には i[r] で FindTeX に対応する null を返却します。t[t]はないので、f は undefinedになります。!s(h) の h は null ですが、 s(null) が falseで 反転してtrueになります。if文はこれで成立して、Array.isArray(h) が動作し、2項演算子は非成立を繰り返します。
次は、packages で [base, newcommand, action] という値が処理されます。
this.Option は
{ FindTeX: null, packages: [ "base", "newcommand", "action", ], digits: { /^(?:[0-9]+(?:\\{,\\}[0-9]{3})*(?:\\.[0-9]*)?|\\.[0-9]+)/ }, maxBuffer: 5120, formatError: function(t, e) { return t.formatError(e) }, }
となります。
他にも
this.preFilters = { items: [],} this.postFilters = { items: [],}
という値も設定されます。
nは以下のような値になっています。
e { options: { inlineMath: 0: ['$', '$'], 1: ['\(', '\)'] displayMath: 0: ['$$', '$$'], 1: ['\[', '\]'], processEscapes: true, processEnvironments: true, processRefs: true}, end: { $:(3) ['$' , false, /\$|\\(?:[a-zA-Z]|.)|[{}]/g], \(:(3) ['\)', false, /\\\)|\\(?:[a-zA-Z]|.)|[{}]/g], $$:(3) ['$$', true, /\\$\$|\\(?:[a-zA-Z]|.)|[{}]/g], \[:(3) ['\]', true, /\\\]|\\(?:[a-zA-Z]|.)|[{}]/g] }, sub: 2, env: 1, start: /\$\$|\\\(|\\\[|\$|\\begin\s*\{([^}]*)\}|(\\([\\$])|(\\(?:eq)?ref\s*\{[^}]*\}))/g, … }
h = ['base', 'newcommand', 'action']、 f = t { initMethod: e {関数}, configMethod : e { item : []} configratons : t { item : [0 : item t(関数), priority: 5], [1 : item t(関数), priority: 5], [2 : item t(関数), priority: 5], }, parsers: ["tex",], handlers: t map[{"character" => t}, items: {beginEnv: ƒ, start: ƒ, stop: ƒ, open: ƒ, close: ƒ, array: ƒ, call: ƒ, dot: ƒ, end: ƒ, eqnarray: ƒ, equation: ƒ, fn: ƒ, left: ƒ, middle: ƒ, mml: ƒ, noscript: ƒ, not: ƒ, position: ƒ, prime: ƒ, right: ƒ, style: ƒ, subsup: ƒ, }, nodes: {}, options:{maxMacros: 1000, baseURL: "",}
} d は t {options: {FindTeX: null, packages: Array(3), digits: /^(?:[0-9]+(?:\\{,\\}[0-9]{3})*(?:\\.[0-9]*)?|\\.[0-9]+)/, maxBuffer: 5120, formatError: ƒ, …}, packageData: Map(0) {size: 0}, parsers: {}, root: null, nodeLists: {…}, error : false, handlers t{map : Map(4) {size: 4, character => t {_configura…, …}, delimiter => t {_configura…, …}, macro => t {…}, environment => t {…}}}, itemFactory : e {defaultKind: 'dummy', nodeMap: Map(24), node: {…}, configuration: t}, nodeFactory : t {mmlFactory: null, factory: {…}, configuration: t} } 上記の値は\\とすべきものを\にしています。それでも割かし理解しづらい。
再び e.MathJax.config.startup.ready() { f() > c }
function e(r) {
void 0 === r && (r = {});
var n = this,
o = s((0, c.separateOptions)(r, e.OPTIONS, u.FindTeX.OPTIONS), 3),
i = o[0],
a = o[1],
l = o[2];
(n = t.call(this, a) || this).findTeX = n.options.FindTeX || new u.FindTeX(l);
var h = n.options.packages,
f = n.configuration = e.configure(h),
d = n._parseOptions = new m.default(f, [n.options, y.TagsFactory.OPTIONS]);
return
(0, c.userOptions)(d.options, i),
/* ここから追跡再開 */
f.config(n),
e.tags(d, f),
n.postFilters.add(p.default. cleanSubSup, -6),
n.postFilters.add(p.default. setInherited, -5),
n.postFilters.add(p.default. moveLimits, -4),
n.postFilters.add(p.default. cleanStretchy, -3),
n.postFilters.add(p.default. cleanAttributes, -2),
n.postFilters.add(p.default.combineRelations, -1),
n
}
n は以下のような値になっています。HTMLに定義した config 情報とデフォルト値を結合するような処理が preLoad では処理されています。
n =
{
adaptor: null,
mmlFactory: null,
options: {
FindTeX: null,
packages: ["base", "newcommand", "action",],
digits: { },
maxBuffer: 5120,
formatError:
function(t, e) {
return t.formatError(e)
},
},
preFilters: { items: [ ], },
postFilters: { items: [ ], },
findTeX: {
options: {
inlineMath : [[ "$", "$",], [ "\\(", "\\)",],],
displayMath: [[ "$$", "$$",], [ "\\[", "\\]",],],
processEscapes: true,
processEnvironments: true,
processRefs: true,
},
end: { $: [ "$", false, { },],
"\\(": ["\\)", false, { },],
$$: [ "$$", true, { },],
"\\[": ["\\]", true, { },],
},
sub: 2,
env: 1,
start: { },
hasPatterns: true,
},
}
f.config(n) で以下の関数が実行されます。t は CONFIG 値
config = function(t) {
var e, r;
this.configMethod.execute(this, t);
try {
for(var o = n(this.configurations), i = o.next(); !i.done; i = o.next()) {
var s = i.value;
this.addFilters(t, s.item)
}
} catch(t) {
e = {
error: t
}
} finally {
try {
i && !i.done && (r = o.return) && r.call(o)
} finally {
if(e) throw e.error
}
}
}
this.configMethod.execute は以下のような関数です。
.execute = function() {
for(var t, e, r = [], n = 0; n < arguments.length; n++)
r[n] = arguments[n];
try {
for(var o = i(this), l = o.next(); !l.done; l = o.next()) {
var c = l.value;
var u = c.item.apply(c, a([], s(r), !1));
if(!1 === u) return !1
}
} catch(e) {
t = {
error: e
}
} finally {
try {
l && !l.done && (e = o.return) && e.call(o)
} finally {
if(t) throw t.error
}
}
return !0
}
nを引数に呼び出されますが、excuteでは関数名の横の引数では受け取らず、arguments で制御します。r[n] は r[0] に this 値が、r[1] に n が格納されます。そして try で、呼び出し元のthis 値をひとつづつ取り出して c へ。
c.item 関数自体にcと2番目の引数を配列のように受け取った結果を返すのが apply です。c.item を thisとすると。c = this(c, 2番目の配列の要素1) → c = this(c, 2番目の配列の要素2) → … → c = this(c, 2番目の配列の要素n) と繰り返し処理されます。a([], [0:{math : e, document : e, data : t }], false) という関数が返す配列です。
結果的に c = this( c, [0 : {math : { …, …, …, }, document : { …, …, …, }, data : { …, …, …, } });というような処理がされます。結局 preload時は、undefined だそうな。返り値が 0 だと return false が発生します。
c はこんな関数。とはいいつつも次々と変化します。
function(t) {
var e = t.data;
e.error || (o(e, "sub", "sup"), o(e, "under", "over"))
}
引数の t.data を e に格納して e.error が 0 なら (o(e, "sub", "sup"), o(e, "under", "over")) を実行という感じ。確かに返り値がないね。0 になるときってどんなときなんだろう。この場合はわからん。次の関数とかでなにかおこるのやもしれませんね。
c を列挙してみます。
1:
function(t) {
t.data.root.setInheritedAttributes({}, t.math.display, 0, !1)
}
2:
function(t) {
var e, r, n = t.data;
try {
for(var o = c(n.getList("nonscript")), i = o.next(); !i.done; i = o.next()) {
var s = i.value;
if(s.attributes.get("scriptlevel") > 0) {
var a = s.parent;
if(a.childNodes.splice(a.childIndex(s), 1), n.removeFromList(s.kind, [s]), s.isKind("mrow")) {
var l = s.childNodes[0];
n.removeFromList("mstyle", [l]), n.removeFromList("mspace", l.childNodes[0].childNodes)
}
} else s.isKind("mrow") && (s.parent.replaceChild(s.childNodes[0], s), n.removeFromList("mrow", [s]))
}
} catch(t) {
e = {
error: t
}
} finally {
try {
i && !i.done && (r = o.return) && r.call(o)
} finally {
if(e) throw e.error
}
}
}
3:
function(t) {
var e = t.data;
i(e, "munderover", "msubsup"), i(e, "munder", "msub"), i(e, "mover", "msup")
}
4:
function(t) {
var e, r, o = t.data;
try {
for(var i = n(o.getList("fixStretchy")), s = i.next(); !s.done; s = i.next()) {
var l = s.value;
if(a.default.getProperty(l, "fixStretchy")) {
var c = a.default.getForm(l);
c && c[3] && c[3].stretchy && a.default.setAttribute(l, "stretchy", !1);
var u = l.parent;
if(!(a.default.getTexClass(l) || c && c[2])) {
var p = o.nodeFactory.create("node", "TeXAtom", [l]);
u.replaceChild(p, l), p.inheritAttributesFrom(l)
}
a.default.removeProperties(l, "fixStretchy")
}
}
} catch(t) {
e = {
error: t
}
} finally {
try {
s && !s.done && (r = i.return) && r.call(i)
} finally {
if(e) throw e.error
}
}
}
5:
function(t) {
t.data.root.walkTree((function(t, e) {
var r, o, i = t.attributes;
if(i) {
var s = new Set((i.get("mjx-keep-attrs") || "").split(/ /));
delete i.getAllAttributes()["mjx-keep-attrs"];
try {
for(var a = n(i.getExplicitNames()), l = a.next(); !l.done; l = a.next()) {
var c = l.value;
s.has(c) || i.attributes[c] !== t.attributes.getInherited(c) || delete i.attributes[c]
}
} catch(t) {
r = {
error: t
}
} finally {
try {
l && !l.done && (o = a.return) && o.call(a)
} finally {
if(r) throw r.error
}
}
}
}), {})
}
6:
{}
と、いろいろ処理をします。
関数は config に戻って、繰り返しの要素変数1-3回目 s は addFileters(t, s.item)
s = t {name: 'action', handler: {…}, fallback: {…}, items: { }, tags: {…}, …} t {name: 'newcommand', handler: {…}, fallback: {…}, items: {…}, tags: {…}, …} t {name: 'base', handler: {…}, fallback: {…}, items: {…}, tags: {…}, …}
t = e {adaptor: null, mmlFactory: null, options: {…}, preFilters: e, postFilters: e, …}
function(t, e) {
var r, i, s, a;
try {
for(var l = n(e.preprocessors), c = l.next(); !c.done; c = l.next()) {
var u = o(c.value, 2),
p = u[0],
h = u[1];
t.preFilters.add(p, h)
}
} catch(t) {
r = {
error: t
}
} finally {
try {
c && !c.done && (i = l.return) && i.call(l)
} finally {
if(r) throw r.error
}
}
try {
for(var f = n(e.postprocessors), d = f.next(); !d.done; d = f.next()) {
var m = o(d.value, 2),
y = m[0];
h = m[1];
t.postFilters.add(y, h)
}
} catch(t) {
s = {
error: t
}
} finally {
try {
d && !d.done && (a = f.return) && a.call(f)
} finally {
if(s) throw s.error
}
}
}
.preprocessors .postprocessorsも値がないので何も起こらないですね。
e.tags(d, f) 関数というを処理します。以下のような関数です。
tags = function(t, e) {
y.TagsFactory.addTags(e.tags),
y.TagsFactory.setDefault(t.options.tags),
t.tags = y.TagsFactory.getDefault(),
t.tags.configuration = t
}
このとき d = t, f = e は
t = t {options: {…}, packageData: Map(0), parsers: Array(0), root: null, nodeLists: {…}, …} e = t {initMethod: e, configMethod: e, configurations: t, parsers: Array(1), handlers: t, tags : {base:{ function() }}}
といった値です。
y.TagsFactory.addTags = function(e) {
var r, n;
try {
for(var o = i(Object.keys(e)), s = o.next(); !s.done; s = o.next()) {
var a = s.value;
t.add(a, e[a])
}
} catch(t) {
r = {
error: t
}
} finally {
try {
s && !s.done && (n = o.return) && n.call(o)
} finally {
if(r) throw r.error
}
}
}
e.tags は 関数で以下のようなものです。関数が引数になります。
{
base:{
tags = function() {
return null !== t && t.apply(this, arguments) || this
}
}
}
ひとつづつ、t.add(a, e[a]) という処理をする。t.set('base', e['base']) になり、e の base : e['base']が設定される。結果としてe() { return null !== t && t.apply(this, arguments) || this }
が設定される。t に何か設定されていたら、this = t(for (i = arguments; !i.done; i.next())i.value())みたいなことが実行されるってことだな。t の関数がなければthis を返す。
のこりは
y.TagsFactory.setDefault(t.options.tags), t.tags = y.TagsFactory.getDefault(), t.tags.configuration = t
で、y.TagsFactory.setDefault は r = t.options.tags; という処理で、r = 'none' のような処理。
y.TagsFactory.getDefault() = function() { t.create(r) } は
t.create(t) = function(t) {
var n = e.get(t) || e.get(r);
if(!n)
throw Error("Unknown tags class");
return new n
}
n はこんな関数値です。
function e() {
return null !== t && t.apply(this, arguments) || this
}
他にもメンバ関数 .constructor .autoTag .getTag
.t = funection(){
this.counter = 0, this.allCounter = 0, this.configuration = null, this.ids = {}, this.allIds = {}, this.labels = {}, this.allLabels = {}, this.redo = !1, this.refUpdate = !1, this.currentTag = new c, this.history = [], this.stack = [], this.enTag = function(t, e) { var r = this.configuration.nodeFactory, n = r.create("node", "mtd", [t]), o = r.create("node", "mlabeledtr", [e, n]); return r.create( "node", "mtable", [o], { side: this.configuration.options.tagSide, minlabelspacing: this.configuration.options.tagIndent, displaystyle: !0 }) }
}
がある感じ。
t { error : false, handlers t {map: Map(4)} itemFactory : e {defaultKind: 'dummy', nodeMap: Map(24) { size: 24, 1:start => ƒ e(e, r), 2:stop => ƒ e(), 3:open => ƒ e(), 4:close => ƒ e(), 5:prime => ƒ e(), 6:subsup => ƒ e(), 7:over => ƒ e(), 8:left => ƒ e(), 9:middle => ƒ e(), 10:right => ƒ e(), 11:begin => ƒ e(), 12:end => ƒ e(), 13:style => ƒ e(), 14:position => ƒ e(), 15:cell => ƒ e(), 16:mml => ƒ e(), 17:fn => ƒ e(), 18:not => ƒ e(), 19:nonscript => ƒ e(), 20:dots => ƒ e(), 21:array => ƒ e(), 22:eqnarray => ƒ e(), 23:equation => ƒ e(), beginEnv => ƒ e(), …}, node: {beginEnv: ƒ, start: ƒ, stop: ƒ, open: ƒ, close: ƒ, …}, configuration: t {options: {…}, packageData: [], parsers: [], root: null, nodeLists: {…}, } } nodeFactory : t {mmlFactory: null, factory: {…}, configuration: t} nodeList options: { FindTeX: null, packages: Array(3), digits: /^(?:[0-9]+(?:\\{,\\}[0-9]{3})*(?:\\.[0-9]*)?|\\.[0-9]+)/, maxBuffer: 5120, formatError: ƒ, …}, packageData: Map(0) {size: 0}, parser : ƒ () { return this.parsers[0] }, parsers: [], root: null, }
そして最後ですが、 .add = function(e, r) {
void 0 === r && (r = t.DEFAULTPRIORITY); var n = this.items.length; do { n-- } while (n >= 0 && r < this.items[n].priority); return this.items.splice(n + 1, 0, { item: e, priority: r }), e
}
第二引数に優先度が設定されるもので、 e には p.default.cleanSubSup/setInherited/moveLimits/cleanStretchy/cleanAttributes/combineRelationsが設定されます。
e.MathJax.config.startup.ready() { t.defaultReady f() > _() }
次は _ という関数だけど
function _() {
var r = e.CONFIG.output; /* = chtml */
if(!r) return null;
var n = t.constructors[r];
if(!n) throw Error('Output Jax "' + r + '" is not defined (has it been loaded?)');
return new n(e.MathJax.config[r])
}
n = t.constructors['chtml'] で n(e.MathJax.config['chtml']) = {fontURL: 'http://localhost:5500/es5/output/chtml/fonts/woff-v2', font: e}
n = e(e.MathJax.config['chtml']) {
void 0 === e && (e = null);
var r = t.call(this, e, h.CHTMLWrapperFactory, d.TeXFont) || this;
return r.chtmlStyles = null,
r.font.adaptiveCSS(r.options.adaptiveCSS),
r.wrapperUsage = new f.Usage,
r
}
これで r が以下のような値になります。
{ adaptor : null, chtmlStyles : null , cssStyles : t {styles: {cssText : function(){this.getStyleString()}, style : {} } }, factory : e { defaultKind: 'unknown', nodeMap: [ 0 : { "math" => function e() { return null !== t && t.apply(this, arguments) || this } }, 1 : { "mrow" => function e() { return null !== t && t.apply(this, arguments) || this } } 2 : { "inferredMrow" = … }, 3 : { "mi" = … }, 4 : { "mo" = … }, 5 : { "mn" = … }, 6 : { "ms" = … }, 7 : { "mtext" = … }, 8 : { "mspace" = … }, 9 : { "mpadded" = … }, 10 : { "menclose" = … }, 11 : { "mfrac" = … }, 12 : { "msqrt" = … }, 13 : { "mroot" = … }, 14 : { "msub" = … }, 15 : { "msup" = … }, 16 : { "msubsup" = … }, 17 : { "munder" = … }, 18 : { "mover" = … }, 19 : { "munderober" = … }, 20 : { "mmultiscripts" = … }, 21 : { "fenced" = … }, 22 : { "mtable" = … }, 23 : { "mtr" = … }, 24 : { "mlabeledtr" = … }, 25 : { "mtd" = … }, 26 : { "maction" = … }, 27 : { "mglyph" = … }, 28 : { "semantics" = … }, 29 : { "annotation" = … }, 30 : { "annotation-xml" = … }, 31 : { "XML" = … }, 32 : { "TeXAtom" = … }, 33 : { "text" = … }, 34 : { "unknown" = … }, ], node: {mrow : ƒ {}, inferredMrow : …, unknown : ƒ {}}, jax: e {adaptor: null, chtmlStyles : null, font : , name : , options : {scale: 1, minScale: 0.5, mtextInheritFont: false, merrorInheritFont: false, mtextFont: , adaptiveCSS : true, cssStyles : null, displayAlign : 'center', displayIndent : '0', exFactor : 0.5, font : e {variant: {…}, delimiters: {…}, cssFontMap: {…}, remapChars: {…}, skewIcFactor: 0.75, …} matchFontHeight : true, mathmlSpacing : false, merrorFont : 'serif', skipAttributes : {}, wrapperFactory : null, }, postFilters : e, unknownCache : , factory: e {defaultKind: 'unknown', nodeMap: Map(35), node: {…}, jax: e}, cssStyles: t {styles: {…}}, … } }, font : e {charUsage : , cssFamilyPrefix : 'MJXZERO', cssFontMap : , delimiters : , delimUsage : , options : , params : { axis_height : 0.25, big_op_spacing1 : 0.111, big_op_spacing2 : 0.167, big_op_spacing3 : 0.2, big_op_spaging4 : 0.6, big_op_spacing5 : 0.1, delmi1: 2.39, delmi2 : 1, delimiterfactor : 901, delimitershortfall : 0.3, denom1 : 0.686, denom2 : 0.345, extra_ic : 0.033, min_rule_thickness : 1.25, nulldelimiterspace : 0.12, num1 : 0.676, num2 : 0.394, num3 : 0.444, quad : 1, rule_thickness : 0.06, scriptspace : 0.05, separation_factor : 1.75, sub_drop : 0.05, sub1 : 0.15, sub2 : 0.247, sup_drop : 0.386, sup1 : 0.413, sup2 : 0.363, sup3 : 0.289, surd_height : 0.075, x_height : 0.442, }, remapChars : , sizeVariants : , skewIcFactor : , stretchVariants : ['-size4'], styles : , name : { return this.constructor.NAME }, options : { scale : 1, minScale : 0.5, mtexInheritFont : false, mtextFont: , adaptiveCSS : true, displayAlign : 'center', displayIndent : '0', exFactor : 0.5, matchFontHeight : true, mathmlSpacing : false, merrorFont : 'serif', merrorInheritFont : false, mtexFont : , skipAttributes : {}, wrapperFactory : null }, postFilters : e {items : []}, unknownCache : Map[] {size : 0}, wrapperUsage : t {used: Set(0), needsUpdate: Array(0)}
e.MathJax.config.startup.ready() { t.defaultReady f() > S() }
S = function(){
var r = e.CONFIG.adaptor; /* 'browserAdaptor' */
if(!r || "none" === r) return null;
var n = t.constructors[r];
if(!n) throw Error('DOMAdaptor "' + r + '" is not defined (has it been loaded?)');
return n(e.MathJax.config[r])
}
n は function() { return new n.HTMLAdaptor(window) } となります。この n に e.MathJax.config['browserAdaptor'] のような値を引数にして実行したものを返します。undefined でした。返却されるのは e {document: #document, window: Window, parser: DOMParser} のような値です。
t.input = v(), t.output = _(), t.adaptor = S() だけで、まぁ、長かったな。
t.handler && l.handlers.unregister(t.handler)
e.MathJax.config.startup.ready() { t.defaultReady f() > M() }
t.handlers に格納されるために実行する M() は、以下のような関数です。
M = function(){
var r, n, i = e.CONFIG.handler; /* 'HTMLHandler' */
if(!i || "none" === i || !t.adaptor) return null;
var s = t.constructors[i];
if(!s) throw Error('Handler "' + i + '" is not defined (has it been loaded?)');
var a = new s(t.adaptor, 5);
try {
for(var l = o(u), c = l.next(); !c.done; c = l.next()) {
a = c.value.item(a)
}
} catch(t) {
r = {
error: t
}
} finally {
try {
c && !c.done && (n = l.return) && n.call(l)
} finally {
if(r) throw r.error
}
}
return a
}
e.CONFIG.handler は何も設定されていなければ null を返しますが、 'HTMLHandler' がされていますので、処理は継続されます。
t.constructors[i] = function(){
var e = null !== t && t.apply(this, arguments) || this;
return e.documentClass = s.HTMLDocument, e
}
をt.adaptor, 5という引数で実行し、その後のfor文で使うための値を a に取得します。t 関数で this = t(this, t.adaptor) → this = t(this, 5) という値を算出して e に格納します。この時の t は呼び出されたときの t とは異なる値です。以下のような関数です。
t(t, e) {
void 0 === e && (e = 5), /* e = 0 なら 5 に修正、その他の値ならそのまま。 */
this.documentClass = i,
this.adaptor = t, /* t.adpter */
this.priority = e /* 第二引数 */
}
i はfunction() { return null !== t && t.apply(this, arguments) || this } このような関数です。これが this.documentClass に格納します。
そして e.documentClass = s.HTMLDocument に設定されていますので、この i は上書きされているように思えます。そのようにした e を返しているので、 e は 以下のような値になっていると思います。
e {documentClass => {function() = s.HTMLDocument = function e(e, r, n) { var o = this, i = s((0, c.separateOptions)(n, h.HTMLDomStrings.OPTIONS), 2), a = i[0], l = i[1]; return(o = t.call(this, e, r, a) || this).domStrings = o.options.DomStrings || new h.HTMLDomStrings(l), o.domStrings.adaptor = r, o.styles = [], o } }, KIND : 'HTML' OPTIONS:{OutputJax: null, InputJax: null, MmlFactory: null, MathList: e() {return null !== t && t.apply(this, arguments) || this}, MathItem: e(e, r, n, o, i) { return void 0 === n && (n = !0), void 0 === o && (o = { node: null, n: 0, delim: "" }), void 0 === i && (i = { node: null, n: 0, delim: "" }), t.call(this, e, r, n, o, i) || this }, compileError : ƒ, DomStrings : null, renderAction : a {find: [ 10, 'findMath', , false], compile: [ 20], metrics: [ 100, getMetrics, , false], typeset: [150], update: [ 200, 'updateDocument', false], styles: [ 201, , 'updateStyleSheet, false], }, typesetError : ƒ, } }, adaptor: e {document: #document, window: Window, parser: DOMParser}, priority: 5 }
上記の値が e を経由して a に格納され、返されます。for文でo(u)の繰り返しで得られる要素c.value.item(a)の最後の処理がaに格納されます。
o(u)は2つの要素を持ちますが、最初は
function(t) { return(0, _n.AssistiveMmlHandler)(t) }
AssistiveMmlHandler = function(t) {
return t.documentClass = d(t.documentClass),
t
}
次は
function(t) { return(0, gn.MenuHandler)(t) }
で、a には gn.MenuHandler)(a)という値が得られる。
gn.MenuHandlerは以下のような関数
function(t) {
return t.documentClass = d(t.documentClass),
t
}
d は
function d(t) {
var e;
return e = function(t) { /* run */
function e() {
for(var e = [], r = 0; r < arguments.length; r++) e[r] = arguments[r];
var n = t.apply(this, a([], s(e), !1)) || this;
n.menu = new n.options.MenuClass(n, n.options.menuOptions);
var o = n.constructor.ProcessBits;
return o.has("context-menu") || o.allocate("context-menu"), n.options.MathItem = f(n.options.MathItem), n
}
return o(e, t), e.prototype.addMenu = function() { /* run */
var t, e;
if(!this.processed.isSet("context-menu")) {
try {
for(var r = l(this.math), n = r.next(); !n.done; n = r.next()) {
n.value.addMenu(this)
}
} catch(e) {
t = {
error: e
}
} finally {
try {
n && !n.done && (e = r.return) && e.call(r)
} finally {
if(t) throw t.error
}
}
this.processed.set("context-menu")
}
return this
}, e.prototype.checkLoading = function() {
this.menu.isLoading && c.mathjax.retryAfter(this.menu.loadingPromise.catch((function(t) {
return console.log(t)
})));
var t = this.menu.settings;
return t.collapsible && (this.options.enableComplexity = !0, this.menu.checkComponent("a11y/complexity")), t.explorer && (this.options.enableEnrichment = !0, this.options.enableExplorer = !0, this.menu.checkComponent("a11y/explorer")), this
}, e.prototype.state = function(e, r) {
return void 0 === r && (r = !1), t.prototype.state.call(this, e, r), e < u.STATE.CONTEXT_MENU && this.processed.clear("context-menu"), this
}, e.prototype.updateDocument = function() {
return t.prototype.updateDocument.call(this), this.menu.menu.store.sort(), this
}, e
}(t), e.OPTIONS = i(i({
enableEnrichment: !0,
enableComplexity: !0,
enableExplorer: !0,
enrichSpeech: "none",
enrichError: function(t, e, r) {
return console.warn("Enrichment Error:", r)
}
}, t.OPTIONS), {
MenuClass: h.Menu,
menuOptions: h.Menu.OPTIONS,
enableMenu: !0,
sre: t.OPTIONS.sre || (0, p.expandable)({}),
a11y: t.OPTIONS.a11y || (0, p.expandable)({}),
renderActions: (0, p.expandable)(i(i({}, t.OPTIONS.renderActions), {
addMenu: [u.STATE.CONTEXT_MENU],
checkLoading: [u.STATE.UNPROCESSED + 1]
}))
}), e
}
結果、以下のような値になります。
e { documentClass: { function e() { for(var e = [], r = 0; r < arguments.length; r++) e[r] = arguments[r]; var n = t.apply(this, a([], s(e), !1)) || this; n.menu = new n.options.MenuClass(n, n.options.menuOptions); var o = n.constructor.ProcessBits; return o.has("context-menu") || o.allocate("context-menu"), n.options.MathItem = f(n.options.MathItem), n }, { a11y: a, compilerError: ƒ DomStrings: null, enableAssistveMml: true, enableEnrichment: true, enableComplexity: true, enableExplorer: true, enableMenu: true, enrichSpeech: 'none', enrichError: ƒ, InputJax: null, MathItem: ƒ, MathList:, MenuClass:, menuOptions: { settings: { texHints: true, semantics: false, zoom: 'NoZoom', zscale: '200%', renderer: 'CHTML', … }, jax: {CHTML: null, SVG: null}, annotationTypes: a }, MmlFactory: null, OutputJax: null, renderActions: a { find: Array(4), compile: Array(1), metrics: Array(4), typeset: Array(1), update: Array(3), … } } } adaptor: e, priority: 5 }
シンプルなようで非常に複雑です。謎めいた処理です。また後程確認をするとしましょう。
e.MathJax.config.startup.ready() { t.defaultReady f() > O() }
function O(r) {
return void 0 === r &&
(r = null),
l.document(
r ||
e.CONFIG.document,
n(
n( {}, e.MathJax.config.options),
{
InputJax: t.input,
OutputJax: t.output
}
)
)
}
r = 0 なら、r = nullとして、返却値の対象の l.document(e.CONFIG.document, n())の演算を行います。以下のような値が返ってきます。
e { adaptor: , document: #document, domStrings: , inputJax: [e, e], kind: options: {…}, math: e {list: s}, menu: , mmlFactory: , outputJax: , processed: e, renderActions: e, styles: , vistor }
l.document(t,r) は次のような関数です。function(t, r) { return e.mathjax.handlers.document(t, r) } で t はe.CONFIG.document です。r は演算されて {InputJax: [e, e], OutputJax: e} といった内容になります。
Input の e は e {adaptor: e, mmlFactory: e, options: {…}, preFilters: e, postFilters: e, …}、Output の e は e {adaptor: e, options: {…}, postFilters: e, factory: e, cssStyles: t, …} のようなものです。
ページ
- 次:MathJaxをデバッグしてJavaScriptの理解を深める ページ2
- MathJaxをデバッグしてJavaScriptの理解を深める ページ3
- MathJaxをデバッグしてJavaScriptの理解を深める ページ4
関連情報