MathEvents.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
  2. /* vim: set ts=2 et sw=2 tw=80: */
  3. /*************************************************************
  4. *
  5. * MathJax/extensions/MathEvents.js
  6. *
  7. * Implements the event handlers needed by the output jax to perform
  8. * menu, hover, and other events.
  9. *
  10. * ---------------------------------------------------------------------
  11. *
  12. * Copyright (c) 2011-2017 The MathJax Consortium
  13. *
  14. * Licensed under the Apache License, Version 2.0 (the "License");
  15. * you may not use this file except in compliance with the License.
  16. * You may obtain a copy of the License at
  17. *
  18. * http://www.apache.org/licenses/LICENSE-2.0
  19. *
  20. * Unless required by applicable law or agreed to in writing, software
  21. * distributed under the License is distributed on an "AS IS" BASIS,
  22. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  23. * See the License for the specific language governing permissions and
  24. * limitations under the License.
  25. */
  26. (function (HUB,HTML,AJAX,CALLBACK,LOCALE,OUTPUT,INPUT) {
  27. var VERSION = "2.7.2";
  28. var EXTENSION = MathJax.Extension;
  29. var ME = EXTENSION.MathEvents = {version: VERSION};
  30. var SETTINGS = HUB.config.menuSettings;
  31. var CONFIG = {
  32. hover: 500, // time required to be considered a hover
  33. frame: {
  34. x: 3.5, y: 5, // frame padding and
  35. bwidth: 1, // frame border width (in pixels)
  36. bcolor: "#A6D", // frame border color
  37. hwidth: "15px", // haze width
  38. hcolor: "#83A" // haze color
  39. },
  40. button: {
  41. x: -6, y: -3, // menu button offsets
  42. wx: -2 // button offset for full-width equations
  43. },
  44. fadeinInc: .2, // increment for fade-in
  45. fadeoutInc: .05, // increment for fade-out
  46. fadeDelay: 50, // delay between fade-in or fade-out steps
  47. fadeoutStart: 400, // delay before fade-out after mouseout
  48. fadeoutDelay: 15*1000, // delay before automatic fade-out
  49. styles: {
  50. ".MathJax_Hover_Frame": {
  51. "border-radius": ".25em", // Opera 10.5 and IE9
  52. "-webkit-border-radius": ".25em", // Safari and Chrome
  53. "-moz-border-radius": ".25em", // Firefox
  54. "-khtml-border-radius": ".25em", // Konqueror
  55. "box-shadow": "0px 0px 15px #83A", // Opera 10.5 and IE9
  56. "-webkit-box-shadow": "0px 0px 15px #83A", // Safari and Chrome
  57. "-moz-box-shadow": "0px 0px 15px #83A", // Forefox
  58. "-khtml-box-shadow": "0px 0px 15px #83A", // Konqueror
  59. border: "1px solid #A6D ! important",
  60. display: "inline-block", position:"absolute"
  61. },
  62. ".MathJax_Menu_Button .MathJax_Hover_Arrow": {
  63. position:"absolute",
  64. cursor:"pointer",
  65. display:"inline-block",
  66. border:"2px solid #AAA",
  67. "border-radius":"4px",
  68. "-webkit-border-radius": "4px", // Safari and Chrome
  69. "-moz-border-radius": "4px", // Firefox
  70. "-khtml-border-radius": "4px", // Konqueror
  71. "font-family":"'Courier New',Courier",
  72. "font-size":"9px",
  73. color:"#F0F0F0"
  74. },
  75. ".MathJax_Menu_Button .MathJax_Hover_Arrow span": {
  76. display:"block",
  77. "background-color":"#AAA",
  78. border:"1px solid",
  79. "border-radius":"3px",
  80. "line-height":0,
  81. padding:"4px"
  82. },
  83. ".MathJax_Hover_Arrow:hover": {
  84. color:"white!important",
  85. border:"2px solid #CCC!important"
  86. },
  87. ".MathJax_Hover_Arrow:hover span": {
  88. "background-color":"#CCC!important"
  89. }
  90. }
  91. };
  92. //
  93. // Common event-handling code
  94. //
  95. var EVENT = ME.Event = {
  96. LEFTBUTTON: 0, // the event.button value for left button
  97. RIGHTBUTTON: 2, // the event.button value for right button
  98. MENUKEY: "altKey", // the event value for alternate context menu
  99. /*************************************************************/
  100. /*
  101. * Enum element for key codes.
  102. */
  103. KEY: {
  104. RETURN: 13,
  105. ESCAPE: 27,
  106. SPACE: 32,
  107. LEFT: 37,
  108. UP: 38,
  109. RIGHT: 39,
  110. DOWN: 40
  111. },
  112. Mousedown: function (event) {return EVENT.Handler(event,"Mousedown",this)},
  113. Mouseup: function (event) {return EVENT.Handler(event,"Mouseup",this)},
  114. Mousemove: function (event) {return EVENT.Handler(event,"Mousemove",this)},
  115. Mouseover: function (event) {return EVENT.Handler(event,"Mouseover",this)},
  116. Mouseout: function (event) {return EVENT.Handler(event,"Mouseout",this)},
  117. Click: function (event) {return EVENT.Handler(event,"Click",this)},
  118. DblClick: function (event) {return EVENT.Handler(event,"DblClick",this)},
  119. Menu: function (event) {return EVENT.Handler(event,"ContextMenu",this)},
  120. //
  121. // Call the output jax's event handler or the zoom handler
  122. //
  123. Handler: function (event,type,math) {
  124. if (AJAX.loadingMathMenu) {return EVENT.False(event)}
  125. var jax = OUTPUT[math.jaxID];
  126. if (!event) {event = window.event}
  127. event.isContextMenu = (type === "ContextMenu");
  128. if (jax[type]) {return jax[type](event,math)}
  129. if (EXTENSION.MathZoom) {return EXTENSION.MathZoom.HandleEvent(event,type,math)}
  130. },
  131. //
  132. // Try to cancel the event in every way we can
  133. //
  134. False: function (event) {
  135. if (!event) {event = window.event}
  136. if (event) {
  137. if (event.preventDefault) {event.preventDefault()} else {event.returnValue = false}
  138. if (event.stopPropagation) {event.stopPropagation()}
  139. event.cancelBubble = true;
  140. }
  141. return false;
  142. },
  143. //
  144. // Keydown event handler. Should only fire on Space key.
  145. //
  146. Keydown: function (event, math) {
  147. if (!event) event = window.event;
  148. if (event.keyCode === EVENT.KEY.SPACE) {
  149. EVENT.ContextMenu(event, this);
  150. };
  151. },
  152. //
  153. // Load the contextual menu code, if needed, and post the menu
  154. //
  155. ContextMenu: function (event,math,force) {
  156. //
  157. // Check if we are showing menus
  158. //
  159. var JAX = OUTPUT[math.jaxID], jax = JAX.getJaxFromMath(math);
  160. var show = (JAX.config.showMathMenu != null ? JAX : HUB).config.showMathMenu;
  161. if (!show || (SETTINGS.context !== "MathJax" && !force)) return;
  162. //
  163. // Remove selections, remove hover fades
  164. //
  165. if (ME.msieEventBug) {event = window.event || event}
  166. EVENT.ClearSelection(); HOVER.ClearHoverTimer();
  167. if (jax.hover) {
  168. if (jax.hover.remove) {clearTimeout(jax.hover.remove); delete jax.hover.remove}
  169. jax.hover.nofade = true;
  170. }
  171. //
  172. // If the menu code is loaded,
  173. // Check if localization needs loading;
  174. // If not, post the menu, and return.
  175. // Otherwise wait for the localization to load
  176. // Otherwse load the menu code.
  177. // Try again after the file is loaded.
  178. //
  179. var MENU = MathJax.Menu; var load, fn;
  180. if (MENU) {
  181. if (MENU.loadingDomain) {return EVENT.False(event)}
  182. load = LOCALE.loadDomain("MathMenu");
  183. if (!load) {
  184. MENU.jax = jax;
  185. var source = MENU.menu.Find("Show Math As").submenu;
  186. source.items[0].name = jax.sourceMenuTitle;
  187. source.items[0].format = (jax.sourceMenuFormat||"MathML");
  188. source.items[1].name = INPUT[jax.inputJax].sourceMenuTitle;
  189. source.items[5].disabled = !INPUT[jax.inputJax].annotationEncoding;
  190. //
  191. // Try and find each known annotation format and enable the menu
  192. // items accordingly.
  193. //
  194. var annotations = source.items[2]; annotations.disabled = true;
  195. var annotationItems = annotations.submenu.items;
  196. annotationList = MathJax.Hub.Config.semanticsAnnotations;
  197. for (var i = 0, m = annotationItems.length; i < m; i++) {
  198. var name = annotationItems[i].name[1]
  199. if (jax.root && jax.root.getAnnotation(name) !== null) {
  200. annotations.disabled = false;
  201. annotationItems[i].hidden = false;
  202. } else {
  203. annotationItems[i].hidden = true;
  204. }
  205. }
  206. var MathPlayer = MENU.menu.Find("Math Settings","MathPlayer");
  207. MathPlayer.hidden = !(jax.outputJax === "NativeMML" && HUB.Browser.hasMathPlayer);
  208. return MENU.menu.Post(event);
  209. }
  210. MENU.loadingDomain = true;
  211. fn = function () {delete MENU.loadingDomain};
  212. } else {
  213. if (AJAX.loadingMathMenu) {return EVENT.False(event)}
  214. AJAX.loadingMathMenu = true;
  215. load = AJAX.Require("[MathJax]/extensions/MathMenu.js");
  216. fn = function () {
  217. delete AJAX.loadingMathMenu;
  218. if (!MathJax.Menu) {MathJax.Menu = {}}
  219. }
  220. }
  221. var ev = {
  222. pageX:event.pageX, pageY:event.pageY,
  223. clientX:event.clientX, clientY:event.clientY
  224. };
  225. CALLBACK.Queue(
  226. load, fn, // load the file and delete the marker when done
  227. ["ContextMenu",EVENT,ev,math,force] // call this function again
  228. );
  229. return EVENT.False(event);
  230. },
  231. //
  232. // Mousedown handler for alternate means of accessing menu
  233. //
  234. AltContextMenu: function (event,math) {
  235. var JAX = OUTPUT[math.jaxID];
  236. var show = (JAX.config.showMathMenu != null ? JAX : HUB).config.showMathMenu;
  237. if (show) {
  238. show = (JAX.config.showMathMenuMSIE != null ? JAX : HUB).config.showMathMenuMSIE;
  239. if (SETTINGS.context === "MathJax" && !SETTINGS.mpContext && show) {
  240. if (!ME.noContextMenuBug || event.button !== EVENT.RIGHTBUTTON) return;
  241. } else {
  242. if (!event[EVENT.MENUKEY] || event.button !== EVENT.LEFTBUTTON) return;
  243. }
  244. return JAX.ContextMenu(event,math,true);
  245. }
  246. },
  247. ClearSelection: function () {
  248. if (ME.safariContextMenuBug) {setTimeout("window.getSelection().empty()",0)}
  249. if (document.selection) {setTimeout("document.selection.empty()",0)}
  250. },
  251. getBBox: function (span) {
  252. span.appendChild(ME.topImg);
  253. var h = ME.topImg.offsetTop, d = span.offsetHeight-h, w = span.offsetWidth;
  254. span.removeChild(ME.topImg);
  255. return {w:w, h:h, d:d};
  256. }
  257. };
  258. //
  259. // Handle hover "discoverability"
  260. //
  261. var HOVER = ME.Hover = {
  262. //
  263. // Check if we are moving from a non-MathJax element to a MathJax one
  264. // and either start fading in again (if it is fading out) or start the
  265. // timer for the hover
  266. //
  267. Mouseover: function (event,math) {
  268. if (SETTINGS.discoverable || SETTINGS.zoom === "Hover") {
  269. var from = event.fromElement || event.relatedTarget,
  270. to = event.toElement || event.target;
  271. if (from && to && (HUB.isMathJaxNode(from) !== HUB.isMathJaxNode(to) ||
  272. HUB.getJaxFor(from) !== HUB.getJaxFor(to))) {
  273. var jax = this.getJaxFromMath(math);
  274. if (jax.hover) {HOVER.ReHover(jax)} else {HOVER.HoverTimer(jax,math)}
  275. return EVENT.False(event);
  276. }
  277. }
  278. },
  279. //
  280. // Check if we are moving from a MathJax element to a non-MathJax one
  281. // and either start fading out, or clear the timer if we haven't
  282. // hovered yet
  283. //
  284. Mouseout: function (event,math) {
  285. if (SETTINGS.discoverable || SETTINGS.zoom === "Hover") {
  286. var from = event.fromElement || event.relatedTarget,
  287. to = event.toElement || event.target;
  288. if (from && to && (HUB.isMathJaxNode(from) !== HUB.isMathJaxNode(to) ||
  289. HUB.getJaxFor(from) !== HUB.getJaxFor(to))) {
  290. var jax = this.getJaxFromMath(math);
  291. if (jax.hover) {HOVER.UnHover(jax)} else {HOVER.ClearHoverTimer()}
  292. return EVENT.False(event);
  293. }
  294. }
  295. },
  296. //
  297. // Restart hover timer if the mouse moves
  298. //
  299. Mousemove: function (event,math) {
  300. if (SETTINGS.discoverable || SETTINGS.zoom === "Hover") {
  301. var jax = this.getJaxFromMath(math); if (jax.hover) return;
  302. if (HOVER.lastX == event.clientX && HOVER.lastY == event.clientY) return;
  303. HOVER.lastX = event.clientX; HOVER.lastY = event.clientY;
  304. HOVER.HoverTimer(jax,math);
  305. return EVENT.False(event);
  306. }
  307. },
  308. //
  309. // Clear the old timer and start a new one
  310. //
  311. HoverTimer: function (jax,math) {
  312. this.ClearHoverTimer();
  313. this.hoverTimer = setTimeout(CALLBACK(["Hover",this,jax,math]),CONFIG.hover);
  314. },
  315. ClearHoverTimer: function () {
  316. if (this.hoverTimer) {clearTimeout(this.hoverTimer); delete this.hoverTimer}
  317. },
  318. //
  319. // Handle putting up the hover frame
  320. //
  321. Hover: function (jax,math) {
  322. //
  323. // Check if Zoom handles the hover event
  324. //
  325. if (EXTENSION.MathZoom && EXTENSION.MathZoom.Hover({},math)) return;
  326. //
  327. // Get the hover data
  328. //
  329. var JAX = OUTPUT[jax.outputJax],
  330. span = JAX.getHoverSpan(jax,math),
  331. bbox = JAX.getHoverBBox(jax,span,math),
  332. show = (JAX.config.showMathMenu != null ? JAX : HUB).config.showMathMenu;
  333. var dx = CONFIG.frame.x, dy = CONFIG.frame.y, dd = CONFIG.frame.bwidth; // frame size
  334. if (ME.msieBorderWidthBug) {dd = 0}
  335. jax.hover = {opacity:0, id:jax.inputID+"-Hover"};
  336. //
  337. // The frame and menu button
  338. //
  339. var frame = HTML.Element("span",{
  340. id:jax.hover.id, isMathJax: true,
  341. style:{display:"inline-block", width:0, height:0, position:"relative"}
  342. },[["span",{
  343. className:"MathJax_Hover_Frame", isMathJax: true,
  344. style:{
  345. display:"inline-block", position:"absolute",
  346. top:this.Px(-bbox.h-dy-dd-(bbox.y||0)), left:this.Px(-dx-dd+(bbox.x||0)),
  347. width:this.Px(bbox.w+2*dx), height:this.Px(bbox.h+bbox.d+2*dy),
  348. opacity:0, filter:"alpha(opacity=0)"
  349. }}
  350. ]]
  351. );
  352. var button = HTML.Element("span",{
  353. isMathJax: true, id:jax.hover.id+"Menu", className:"MathJax_Menu_Button",
  354. style:{display:"inline-block", "z-index": 1, width:0, height:0, position:"relative"}
  355. },[["span",{
  356. className: "MathJax_Hover_Arrow", isMathJax: true, math: math,
  357. onclick: this.HoverMenu, jax:JAX.id,
  358. style: {
  359. left:this.Px(bbox.w+dx+dd+(bbox.x||0)+CONFIG.button.x),
  360. top:this.Px(-bbox.h-dy-dd-(bbox.y||0)-CONFIG.button.y),
  361. opacity:0, filter:"alpha(opacity=0)"
  362. }
  363. },[["span",{isMathJax:true},"\u25BC"]]]]
  364. );
  365. if (bbox.width) {
  366. frame.style.width = button.style.width = bbox.width;
  367. frame.style.marginRight = button.style.marginRight = "-"+bbox.width;
  368. frame.firstChild.style.width = bbox.width;
  369. button.firstChild.style.left = "";
  370. button.firstChild.style.right = this.Px(CONFIG.button.wx);
  371. }
  372. //
  373. // Add the frame and button
  374. //
  375. span.parentNode.insertBefore(frame,span);
  376. if (show) {span.parentNode.insertBefore(button,span)}
  377. if (span.style) {span.style.position = "relative"} // so math is on top of hover frame
  378. //
  379. // Start the hover fade-in
  380. //
  381. this.ReHover(jax);
  382. },
  383. //
  384. // Restart the hover fade in and fade-out timers
  385. //
  386. ReHover: function (jax) {
  387. if (jax.hover.remove) {clearTimeout(jax.hover.remove)}
  388. jax.hover.remove = setTimeout(CALLBACK(["UnHover",this,jax]),CONFIG.fadeoutDelay);
  389. this.HoverFadeTimer(jax,CONFIG.fadeinInc);
  390. },
  391. //
  392. // Start the fade-out
  393. //
  394. UnHover: function (jax) {
  395. if (!jax.hover.nofade) {this.HoverFadeTimer(jax,-CONFIG.fadeoutInc,CONFIG.fadeoutStart)}
  396. },
  397. //
  398. // Handle the fade-in and fade-out
  399. //
  400. HoverFade: function (jax) {
  401. delete jax.hover.timer;
  402. jax.hover.opacity = Math.max(0,Math.min(1,jax.hover.opacity + jax.hover.inc));
  403. jax.hover.opacity = Math.floor(1000*jax.hover.opacity)/1000;
  404. var frame = document.getElementById(jax.hover.id),
  405. button = document.getElementById(jax.hover.id+"Menu");
  406. frame.firstChild.style.opacity = jax.hover.opacity;
  407. frame.firstChild.style.filter = "alpha(opacity="+Math.floor(100*jax.hover.opacity)+")";
  408. if (button) {
  409. button.firstChild.style.opacity = jax.hover.opacity;
  410. button.firstChild.style.filter = frame.style.filter;
  411. }
  412. if (jax.hover.opacity === 1) {return}
  413. if (jax.hover.opacity > 0) {this.HoverFadeTimer(jax,jax.hover.inc); return}
  414. frame.parentNode.removeChild(frame);
  415. if (button) {button.parentNode.removeChild(button)}
  416. if (jax.hover.remove) {clearTimeout(jax.hover.remove)}
  417. delete jax.hover;
  418. },
  419. //
  420. // Set the fade to in or out (via inc) and start the timer, if needed
  421. //
  422. HoverFadeTimer: function (jax,inc,delay) {
  423. jax.hover.inc = inc;
  424. if (!jax.hover.timer) {
  425. jax.hover.timer = setTimeout(CALLBACK(["HoverFade",this,jax]),(delay||CONFIG.fadeDelay));
  426. }
  427. },
  428. //
  429. // Handle a click on the menu button
  430. //
  431. HoverMenu: function (event) {
  432. if (!event) {event = window.event}
  433. return OUTPUT[this.jax].ContextMenu(event,this.math,true);
  434. },
  435. //
  436. // Clear all hover timers
  437. //
  438. ClearHover: function (jax) {
  439. if (jax.hover.remove) {clearTimeout(jax.hover.remove)}
  440. if (jax.hover.timer) {clearTimeout(jax.hover.timer)}
  441. HOVER.ClearHoverTimer();
  442. delete jax.hover;
  443. },
  444. //
  445. // Make a measurement in pixels
  446. //
  447. Px: function (m) {
  448. if (Math.abs(m) < .006) {return "0px"}
  449. return m.toFixed(2).replace(/\.?0+$/,"") + "px";
  450. },
  451. //
  452. // Preload images so they show up with the menu
  453. //
  454. getImages: function () {
  455. if (SETTINGS.discoverable) {
  456. var menu = new Image();
  457. menu.src = CONFIG.button.src;
  458. }
  459. }
  460. };
  461. //
  462. // Handle touch events.
  463. //
  464. // Use double-tap-and-hold as a replacement for context menu event.
  465. // Use double-tap as a replacement for double click.
  466. //
  467. var TOUCH = ME.Touch = {
  468. last: 0, // time of last tap event
  469. delay: 500, // delay time for double-click
  470. //
  471. // Check if this is a double-tap, and if so, start the timer
  472. // for the double-tap and hold (to trigger the contextual menu)
  473. //
  474. start: function (event) {
  475. var now = new Date().getTime();
  476. var dblTap = (now - TOUCH.last < TOUCH.delay && TOUCH.up);
  477. TOUCH.last = now; TOUCH.up = false;
  478. if (dblTap) {
  479. TOUCH.timeout = setTimeout(TOUCH.menu,TOUCH.delay,event,this);
  480. event.preventDefault();
  481. }
  482. },
  483. //
  484. // Check if there is a timeout pending, i.e., we have a
  485. // double-tap and were waiting to see if it is held long
  486. // enough for the menu. Since we got the end before the
  487. // timeout, it is a double-click, not a double-tap-and-hold.
  488. // Prevent the default action and issue a double click.
  489. //
  490. end: function (event) {
  491. var now = new Date().getTime();
  492. TOUCH.up = (now - TOUCH.last < TOUCH.delay);
  493. if (TOUCH.timeout) {
  494. clearTimeout(TOUCH.timeout);
  495. delete TOUCH.timeout; TOUCH.last = 0; TOUCH.up = false;
  496. event.preventDefault();
  497. return EVENT.Handler((event.touches[0]||event.touch),"DblClick",this);
  498. }
  499. },
  500. //
  501. // If the timeout passes without an end event, we issue
  502. // the contextual menu event.
  503. //
  504. menu: function (event,math) {
  505. delete TOUCH.timeout; TOUCH.last = 0; TOUCH.up = false;
  506. return EVENT.Handler((event.touches[0]||event.touch),"ContextMenu",math);
  507. }
  508. };
  509. /*
  510. * //
  511. * // Mobile screens are small, so use larger version of arrow
  512. * //
  513. * if (HUB.Browser.isMobile) {
  514. * var arrow = CONFIG.styles[".MathJax_Hover_Arrow"];
  515. * arrow.width = "25px"; arrow.height = "18px";
  516. * CONFIG.button.x = -6;
  517. * }
  518. */
  519. //
  520. // Set up browser-specific values
  521. //
  522. HUB.Browser.Select({
  523. MSIE: function (browser) {
  524. var mode = (document.documentMode || 0);
  525. var isIE8 = browser.versionAtLeast("8.0");
  526. ME.msieBorderWidthBug = (document.compatMode === "BackCompat"); // borders are inside offsetWidth/Height
  527. ME.msieEventBug = browser.isIE9; // must get event from window even though event is passed
  528. ME.msieAlignBug = (!isIE8 || mode < 8); // inline-block spans don't rest on baseline
  529. if (mode < 9) {EVENT.LEFTBUTTON = 1} // IE < 9 has wrong event.button values
  530. },
  531. Safari: function (browser) {
  532. ME.safariContextMenuBug = true; // selection can be started by contextmenu event
  533. },
  534. Opera: function (browser) {
  535. ME.operaPositionBug = true; // position is wrong unless border is used
  536. },
  537. Konqueror: function (browser) {
  538. ME.noContextMenuBug = true; // doesn't produce contextmenu event
  539. }
  540. });
  541. //
  542. // Used in measuring zoom and hover positions
  543. //
  544. ME.topImg = (ME.msieAlignBug ?
  545. HTML.Element("img",{style:{width:0,height:0,position:"relative"},src:"about:blank"}) :
  546. HTML.Element("span",{style:{width:0,height:0,display:"inline-block"}})
  547. );
  548. if (ME.operaPositionBug) {ME.topImg.style.border="1px solid"}
  549. //
  550. // Get configuration from user
  551. //
  552. ME.config = CONFIG = HUB.CombineConfig("MathEvents",CONFIG);
  553. var SETFRAME = function () {
  554. var haze = CONFIG.styles[".MathJax_Hover_Frame"];
  555. haze.border = CONFIG.frame.bwidth+"px solid "+CONFIG.frame.bcolor+" ! important";
  556. haze["box-shadow"] = haze["-webkit-box-shadow"] =
  557. haze["-moz-box-shadow"] = haze["-khtml-box-shadow"] =
  558. "0px 0px "+CONFIG.frame.hwidth+" "+CONFIG.frame.hcolor;
  559. };
  560. //
  561. // Queue the events needed for startup
  562. //
  563. CALLBACK.Queue(
  564. HUB.Register.StartupHook("End Config",{}), // wait until config is complete
  565. [SETFRAME],
  566. ["getImages",HOVER],
  567. ["Styles",AJAX,CONFIG.styles],
  568. ["Post",HUB.Startup.signal,"MathEvents Ready"],
  569. ["loadComplete",AJAX,"[MathJax]/extensions/MathEvents.js"]
  570. );
  571. })(MathJax.Hub,MathJax.HTML,MathJax.Ajax,MathJax.Callback,
  572. MathJax.Localization,MathJax.OutputJax,MathJax.InputJax);