diff options
Diffstat (limited to 'js/mathjax/extensions/MathZoom.js')
-rw-r--r-- | js/mathjax/extensions/MathZoom.js | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/js/mathjax/extensions/MathZoom.js b/js/mathjax/extensions/MathZoom.js new file mode 100644 index 0000000..610746d --- /dev/null +++ b/js/mathjax/extensions/MathZoom.js @@ -0,0 +1,368 @@ +// @license magnet:?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7dn=apache-2.0.txt Apache-2.0 +/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ + +/************************************************************* + * + * MathJax/extensions/MathZoom.js + * + * Implements the zoom feature for enlarging math expressions. It is + * loaded automatically when the Zoom menu selection changes from "None". + * + * --------------------------------------------------------------------- + * + * Copyright (c) 2010-2020 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function (HUB,HTML,AJAX,HTMLCSS,nMML) { + var VERSION = "2.7.9"; + + var CONFIG = HUB.CombineConfig("MathZoom",{ + styles: { + // + // The styles for the MathZoom display box + // + "#MathJax_Zoom": { + position:"absolute", "background-color":"#F0F0F0", overflow:"auto", + display:"block", "z-index":301, padding:".5em", border:"1px solid black", margin:0, + "font-weight":"normal", "font-style":"normal", + "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", + "-webkit-box-sizing":"content-box", // Android ≤ 2.3, iOS ≤ 4 + "-moz-box-sizing":"content-box", // Firefox ≤ 28 + "box-sizing":"content-box", // Chrome, Firefox 29+, IE 8+, Opera, Safari 5.1 + "box-shadow":"5px 5px 15px #AAAAAA", // Opera 10.5 and IE9 + "-webkit-box-shadow":"5px 5px 15px #AAAAAA", // Safari 3 and Chrome + "-moz-box-shadow":"5px 5px 15px #AAAAAA", // Forefox 3.5 + "-khtml-box-shadow":"5px 5px 15px #AAAAAA", // Konqueror + filter: "progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')" // IE + }, + + // + // The styles for the hidden overlay (should not need to be adjusted by the page author) + // + "#MathJax_ZoomOverlay": { + position:"absolute", left:0, top:0, "z-index":300, display:"inline-block", + width:"100%", height:"100%", border:0, padding:0, margin:0, + "background-color":"white", opacity:0, filter:"alpha(opacity=0)" + }, + + "#MathJax_ZoomFrame": { + position:"relative", display:"inline-block", + height:0, width:0 + }, + + "#MathJax_ZoomEventTrap": { + position:"absolute", left:0, top:0, "z-index":302, + display:"inline-block", border:0, padding:0, margin:0, + "background-color":"white", opacity:0, filter:"alpha(opacity=0)" + } + } + }); + + var FALSE, HOVER, EVENT; + MathJax.Hub.Register.StartupHook("MathEvents Ready",function () { + EVENT = MathJax.Extension.MathEvents.Event; + FALSE = MathJax.Extension.MathEvents.Event.False; + HOVER = MathJax.Extension.MathEvents.Hover; + }); + + /*************************************************************/ + + var ZOOM = MathJax.Extension.MathZoom = { + version: VERSION, + settings: HUB.config.menuSettings, + scrollSize: 18, // width of scrool bars + + // + // Process events passed from output jax + // + HandleEvent: function (event,type,math) { + if (ZOOM.settings.CTRL && !event.ctrlKey) return true; + if (ZOOM.settings.ALT && !event.altKey) return true; + if (ZOOM.settings.CMD && !event.metaKey) return true; + if (ZOOM.settings.Shift && !event.shiftKey) return true; + if (!ZOOM[type]) return true; + return ZOOM[type](event,math); + }, + + // + // Zoom on click + // + Click: function (event,math) { + if (this.settings.zoom === "Click") {return this.Zoom(event,math)} + }, + + // + // Zoom on double click + // + DblClick: function (event,math) { + if (this.settings.zoom === "Double-Click" || this.settings.zoom === "DoubleClick") {return this.Zoom(event,math)} + }, + + // + // Zoom on hover (called by MathEvents.Hover) + // + Hover: function (event,math) { + if (this.settings.zoom === "Hover") {this.Zoom(event,math); return true} + return false; + }, + + + // + // Handle the actual zooming + // + Zoom: function (event,math) { + // + // Remove any other zoom and clear timers + // + this.Remove(); HOVER.ClearHoverTimer(); EVENT.ClearSelection(); + + // + // Find the jax + // + var JAX = MathJax.OutputJax[math.jaxID]; + var jax = JAX.getJaxFromMath(math); + if (jax.hover) {HOVER.UnHover(jax)} + + // + // Create the DOM elements for the zoom box + // + var container = this.findContainer(math); + var Mw = Math.floor(.85*container.clientWidth), + Mh = Math.max(document.body.clientHeight,document.documentElement.clientHeight); + if (this.getOverflow(container) !== "visible") {Mh = Math.min(container.clientHeight,Mh)} + Mh = Math.floor(.85*Mh); + var div = HTML.Element( + "span",{id:"MathJax_ZoomFrame"},[ + ["span",{id:"MathJax_ZoomOverlay", onmousedown:this.Remove}], + ["span",{ + id:"MathJax_Zoom", onclick:this.Remove, + style:{visibility:"hidden", fontSize:this.settings.zscale} + },[["span",{style:{display:"inline-block", "white-space":"nowrap"}}]] + ]] + ); + var zoom = div.lastChild, span = zoom.firstChild, overlay = div.firstChild; + math.parentNode.insertBefore(div,math); math.parentNode.insertBefore(math,div); // put div after math + if (span.addEventListener) {span.addEventListener("mousedown",this.Remove,true)} + var eW = zoom.offsetWidth || zoom.clientWidth; Mw -= eW; Mh -= eW; + zoom.style.maxWidth = Mw+"px"; zoom.style.maxHeight = Mh+"px"; + + if (this.msieTrapEventBug) { + var trap = HTML.Element("span",{id:"MathJax_ZoomEventTrap", onmousedown:this.Remove}); + div.insertBefore(trap,zoom); + } + + // + // Display the zoomed math + // + if (this.msieZIndexBug) { + // MSIE doesn't do z-index properly, so move the div to the document.body, + // and use an image as a tracker for the usual position + var tracker = HTML.addElement(document.body,"img",{ + src:"about:blank", id:"MathJax_ZoomTracker", width:0, height:0, + style:{width:0, height:0, position:"relative"} + }); + div.style.position = "relative"; + div.style.zIndex = CONFIG.styles["#MathJax_ZoomOverlay"]["z-index"]; + div = tracker; + } + + var bbox = JAX.Zoom(jax,span,math,Mw,Mh); + + // + // Fix up size and position for browsers with bugs (IE) + // + if (this.msiePositionBug) { + if (this.msieSizeBug) + {zoom.style.height = bbox.zH+"px"; zoom.style.width = bbox.zW+"px"} // IE8 gets the dimensions completely wrong + if (zoom.offsetHeight > Mh) {zoom.style.height = Mh+"px"; zoom.style.width = (bbox.zW+this.scrollSize)+"px"} // IE doesn't do max-height? + if (zoom.offsetWidth > Mw) {zoom.style.width = Mw+"px"; zoom.style.height = (bbox.zH+this.scrollSize)+"px"} + } + if (this.operaPositionBug) {zoom.style.width = Math.min(Mw,bbox.zW)+"px"} // Opera gets width as 0? + if (zoom.offsetWidth > eW && zoom.offsetWidth-eW < Mw && zoom.offsetHeight-eW < Mh) + {zoom.style.overflow = "visible"} // don't show scroll bars if we don't need to + this.Position(zoom,bbox); + if (this.msieTrapEventBug) { + trap.style.height = zoom.clientHeight+"px"; trap.style.width = zoom.clientWidth+"px"; + trap.style.left = (parseFloat(zoom.style.left)+zoom.clientLeft)+"px"; + trap.style.top = (parseFloat(zoom.style.top)+zoom.clientTop)+"px"; + } + zoom.style.visibility = ""; + + // + // Add event handlers + // + if (this.settings.zoom === "Hover") {overlay.onmouseover = this.Remove} + if (window.addEventListener) {addEventListener("resize",this.Resize,false)} + else if (window.attachEvent) {attachEvent("onresize",this.Resize)} + else {this.onresize = window.onresize; window.onresize = this.Resize} + + // + // Let others know about the zoomed math + // + HUB.signal.Post(["math zoomed",jax]); + + // + // Canel further actions + // + return FALSE(event); + }, + + // + // Set the position of the zoom box and overlay + // + Position: function (zoom,bbox) { + zoom.style.display = "none"; // avoids getting excessive width in Resize() + var XY = this.Resize(), x = XY.x, y = XY.y, W = bbox.mW; + zoom.style.display = ""; + var dx = -W-Math.floor((zoom.offsetWidth-W)/2), dy = bbox.Y; + zoom.style.left = Math.max(dx,10-x)+"px"; zoom.style.top = Math.max(dy,10-y)+"px"; + if (!ZOOM.msiePositionBug) {ZOOM.SetWH()} // refigure overlay width/height + }, + + // + // Handle resizing of overlay while zoom is displayed + // + Resize: function (event) { + if (ZOOM.onresize) {ZOOM.onresize(event)} + var div = document.getElementById("MathJax_ZoomFrame"), + overlay = document.getElementById("MathJax_ZoomOverlay"); + var xy = ZOOM.getXY(div), obj = ZOOM.findContainer(div); + if (ZOOM.getOverflow(obj) !== "visible") { + overlay.scroll_parent = obj; // Save this for future reference. + var XY = ZOOM.getXY(obj); // Remove container position + xy.x -= XY.x; xy.y -= XY.y; + XY = ZOOM.getBorder(obj); // Remove container border + xy.x -= XY.x; xy.y -= XY.y; + } + overlay.style.left = (-xy.x)+"px"; overlay.style.top = (-xy.y)+"px"; + if (ZOOM.msiePositionBug) {setTimeout(ZOOM.SetWH,0)} else {ZOOM.SetWH()} + return xy; + }, + SetWH: function () { + var overlay = document.getElementById("MathJax_ZoomOverlay"); + if (!overlay) return; + overlay.style.display = "none"; // so scrollWidth/Height will be right below + var doc = overlay.scroll_parent || document.documentElement || document.body; + overlay.style.width = doc.scrollWidth + "px"; + overlay.style.height = Math.max(doc.clientHeight,doc.scrollHeight) + "px"; + overlay.style.display = ""; + }, + findContainer: function (obj) { + obj = obj.parentNode; + while (obj.parentNode && obj !== document.body && ZOOM.getOverflow(obj) === "visible") + {obj = obj.parentNode} + return obj; + }, + // + // Look up CSS properties (use getComputeStyle if available, or currentStyle if not) + // + getOverflow: (window.getComputedStyle ? + function (obj) {return getComputedStyle(obj).overflow} : + function (obj) {return (obj.currentStyle||{overflow:"visible"}).overflow}), + getBorder: function (obj) { + var size = {thin: 1, medium: 2, thick: 3}; + var style = (window.getComputedStyle ? getComputedStyle(obj) : + (obj.currentStyle || {borderLeftWidth:0,borderTopWidth:0})); + var x = style.borderLeftWidth, y = style.borderTopWidth; + if (size[x]) {x = size[x]} else {x = parseInt(x)} + if (size[y]) {y = size[y]} else {y = parseInt(y)} + return {x:x, y:y}; + }, + // + // Get the position of an element on the page + // + getXY: function (div) { + var x = 0, y = 0, obj; + obj = div; while (obj.offsetParent) {x += obj.offsetLeft; obj = obj.offsetParent} + if (ZOOM.operaPositionBug) {div.style.border = "1px solid"} // to get vertical position right + obj = div; while (obj.offsetParent) {y += obj.offsetTop; obj = obj.offsetParent} + if (ZOOM.operaPositionBug) {div.style.border = ""} + return {x:x, y:y}; + }, + + // + // Remove zoom display and event handlers + // + Remove: function (event) { + var div = document.getElementById("MathJax_ZoomFrame"); + if (div) { + var JAX = MathJax.OutputJax[div.previousSibling.jaxID]; + var jax = JAX.getJaxFromMath(div.previousSibling); + HUB.signal.Post(["math unzoomed",jax]); + div.parentNode.removeChild(div); + div = document.getElementById("MathJax_ZoomTracker"); + if (div) {div.parentNode.removeChild(div)} + if (ZOOM.operaRefreshBug) { + // force a redisplay of the page + // (Opera doesn't refresh properly after the zoom is removed) + var overlay = HTML.addElement(document.body,"div",{ + style:{position:"fixed", left:0, top:0, width:"100%", height:"100%", + backgroundColor:"white", opacity:0}, + id: "MathJax_OperaDiv" + }); + document.body.removeChild(overlay); + } + if (window.removeEventListener) {removeEventListener("resize",ZOOM.Resize,false)} + else if (window.detachEvent) {detachEvent("onresize",ZOOM.Resize)} + else {window.onresize = ZOOM.onresize; delete ZOOM.onresize} + } + return FALSE(event); + } + + }; + + + /*************************************************************/ + + HUB.Browser.Select({ + MSIE: function (browser) { + var mode = (document.documentMode || 0); + var isIE9 = (mode >= 9); + ZOOM.msiePositionBug = !isIE9; + ZOOM.msieSizeBug = browser.versionAtLeast("7.0") && + (!document.documentMode || mode === 7 || mode === 8); + ZOOM.msieZIndexBug = (mode <= 7); + ZOOM.msieInlineBlockAlignBug = (mode <= 7); + ZOOM.msieTrapEventBug = !window.addEventListener; + if (document.compatMode === "BackCompat") {ZOOM.scrollSize = 52} // don't know why this is so far off + if (isIE9) {delete CONFIG.styles["#MathJax_Zoom"].filter} + }, + + Opera: function (browser) { + ZOOM.operaPositionBug = true; + ZOOM.operaRefreshBug = true; + } + }); + + ZOOM.topImg = (ZOOM.msieInlineBlockAlignBug ? + HTML.Element("img",{style:{width:0,height:0,position:"relative"},src:"about:blank"}) : + HTML.Element("span",{style:{width:0,height:0,display:"inline-block"}}) + ); + if (ZOOM.operaPositionBug || ZOOM.msieTopBug) {ZOOM.topImg.style.border="1px solid"} + + /*************************************************************/ + + MathJax.Callback.Queue( + ["StartupHook",MathJax.Hub.Register,"Begin Styles",{}], + ["Styles",AJAX,CONFIG.styles], + ["Post",HUB.Startup.signal,"MathZoom Ready"], + ["loadComplete",AJAX,"[MathJax]/extensions/MathZoom.js"] + ); + +})(MathJax.Hub,MathJax.HTML,MathJax.Ajax,MathJax.OutputJax["HTML-CSS"],MathJax.OutputJax.NativeMML); +// @license-end |