From 2367f0e92bafdc48e706625da058167ac41559e2 Mon Sep 17 00:00:00 2001 From: "Davide P. Cervone" Date: Fri, 19 Aug 2011 09:19:22 -0400 Subject: [PATCH] Preliminary 'discoverable' math implementation. INCOMPLETE: DO NOT USE YET. Only in HTML-CSS mode, and still need to refactor to move event code to common file. Does support mobile devices through tap event. Does not include packed or combined versions yet. --- unpacked/MathJax.js | 22 ++-- unpacked/extensions/MathMenu.js | 21 ++-- unpacked/jax/output/HTML-CSS/config.js | 2 +- unpacked/jax/output/HTML-CSS/jax.js | 136 ++++++++++++++++++++++++- 4 files changed, 164 insertions(+), 17 deletions(-) diff --git a/unpacked/MathJax.js b/unpacked/MathJax.js index c67dd44e7..d08791358 100644 --- a/unpacked/MathJax.js +++ b/unpacked/MathJax.js @@ -30,7 +30,7 @@ if (!window.MathJax) {window.MathJax= {}} if (!MathJax.Hub) { // skip if already loaded MathJax.version = "1.1a"; -MathJax.fileversion = "1.1.10"; +MathJax.fileversion = "1.1.11"; /**********************************************************/ @@ -1025,6 +1025,7 @@ MathJax.fileversion = "1.1.10"; if (AJAX.loadingMathMenu) {return False(event)} var jax = BASE.OutputJax[math.jaxID]; if (!event) {event = window.event} + event.isContextMenu = (type === "ContextMenu"); return jax.HandleEvent(event,type,math); }, // @@ -1054,21 +1055,28 @@ MathJax.fileversion = "1.1.10"; // // Load the contextual menu code, if needed, and post the menu // - ContextMenu: function (event,math) { + ContextMenu: function (event,jax) { + if (jax.hover) { + if (jax.hover.remove) {clearTimeout(jax.hover.remove); delete jax.hover.remove} + jax.hover.nofade = true; + } var MENU = BASE.Menu; if (MENU) { - MENU.jax = BASE.Hub.getJaxFor(math.nextSibling); - MENU.menu.items[1].menu.items[1].name = + MENU.jax = jax; + MENU.menu.Find("Format").menu.items[1].name = (MENU.jax.inputJax.id === "MathML" ? "Original" : MENU.jax.inputJax.id); return MENU.menu.Post(event); } else { if (!AJAX.loadingMathMenu) { AJAX.loadingMathMenu = true; - var ev = {pageX:event.pageX, pageY:event.pageY, clientX:event.clientX, clientY:event.clientY}; + var ev = { + pageX:event.pageX, pageY:event.pageY, + clientX:event.clientX, clientY:event.clientY + }; CALLBACK.Queue( AJAX.Require("[MathJax]/extensions/MathMenu.js"), function () {delete AJAX.loadingMathMenu; if (!BASE.Menu) {BASE.Menu = {}}}, - ["ContextMenu",this,ev,math] // call this function again + ["ContextMenu",this,ev,jax] // call this function again ); } return this.False(event); @@ -1329,6 +1337,8 @@ MathJax.Hub = { ALT: false, // require Alt or Option? CMD: false, // require CMD? Shift: false, // require Shift? + hover: 500, // length of time mouse must be still to count as hover + discoverable: true, // make math menu discoverable on hover? zscale: "200%", // the scaling factor for MathZoom renderer: "", // set when Jax are loaded font: "Auto", // what font HTML-CSS should use diff --git a/unpacked/extensions/MathMenu.js b/unpacked/extensions/MathMenu.js index d44a4f3bd..02ea7567f 100644 --- a/unpacked/extensions/MathMenu.js +++ b/unpacked/extensions/MathMenu.js @@ -176,9 +176,9 @@ if (MENU.isMobile) { HTML.addElement(menu,"img",{ src: MathJax.Ajax.fileURL(MathJax.OutputJax.imageDir+"/CloseX-31.png"), - width: 31, height: 31, + width: 31, height: 31, menu: parent, style: {position:"absolute", top:"-15px", left:"-15px"}, - ontouchstart: MENU.Close, ontouchend: this.False, menu: parent + ontouchstart: MENU.Close, ontouchend: this.False, onmousedown: MENU.Close }); } this.posted = true; @@ -193,7 +193,7 @@ if (x + menu.offsetWidth > document.body.offsetWidth - this.margin) {x = document.body.offsetWidth - menu.offsetWidth - this.margin} if (MENU.isMobile) {x = Math.max(5,x-Math.floor(menu.offsetWidth/2)); y -= 20} - MENU.skipUp = true; + MENU.skipUp = event.isContextMenu; } else { var side = "left", mw = parent.offsetWidth; x = (MENU.isMobile ? 30 : mw - 2); y = 0; @@ -227,6 +227,10 @@ div.parentNode.removeChild(div); if (this.msieBackgroundBug) {detachEvent("onresize",MENU.Resize)} } + if (MENU.jax.hover) { + delete MENU.jax.hover.nofade; + MENU.jax.outputJax.UnHover(MENU.jax); + } }, False: FALSE, @@ -265,10 +269,11 @@ Touchstart: function (event) {return MENU.Event(event,this,"Touchstart")}, Touchend: function (event) {return MENU.Event(event,this,"Touchend")}, Event: function (event,menu,type,force) { - if (MENU.isMobile && type === "Mouseover" && !force) {return FALSE(event)} + if (MENU.skipMouseover && type === "Mouseover" && !force) {return FALSE(event)} if (MENU.skipUp) { if (type.match(/Mouseup|Touchend/)) {delete MENU.skipUp; return FALSE(event)} - if (type.match(/Touchstart/)) {delete MENU.skipUp} + if (type === "Touchstart" || + (type === "Mousedown" && !MENU.skipMousedown)) {delete MENU.skipUp} } if (!event) {event = window.event} var item = menu.menuItem; @@ -759,9 +764,13 @@ delete CONFIG.styles["#MathJax_About"].filter; delete CONFIG.styles[".MathJax_Menu"].filter; } + }, + Firefox: function (browser) { + MENU.skipMouseover = browser.isMobile && browser.versionAtLeast("6.0"); + MENU.skipMousedown = browser.isMobile; } }); - MENU.isMobile = MathJax.Hub.Browser.isMobile; + MENU.isMobile = MathJax.Hub.Browser.isMobile; MENU.noContextMenu = MathJax.Hub.Browser.noContextMenu; /*************************************************************/ diff --git a/unpacked/jax/output/HTML-CSS/config.js b/unpacked/jax/output/HTML-CSS/config.js index 2083a4be7..fddae6a7d 100644 --- a/unpacked/jax/output/HTML-CSS/config.js +++ b/unpacked/jax/output/HTML-CSS/config.js @@ -24,7 +24,7 @@ MathJax.OutputJax["HTML-CSS"] = MathJax.OutputJax({ id: "HTML-CSS", - version: "1.1.8", + version: "1.1.9", directory: MathJax.OutputJax.directory + "/HTML-CSS", extensionDir: MathJax.OutputJax.extensionDir + "/HTML-CSS", autoloadDir: MathJax.OutputJax.directory + "/HTML-CSS/autoload", diff --git a/unpacked/jax/output/HTML-CSS/jax.js b/unpacked/jax/output/HTML-CSS/jax.js index de8dffe0c..4613a4c1a 100644 --- a/unpacked/jax/output/HTML-CSS/jax.js +++ b/unpacked/jax/output/HTML-CSS/jax.js @@ -248,6 +248,27 @@ ".MathJax .MathJax_HitBox": { cursor: "text" }, + + ".MathJax_Hover_Frame": { + "border-radius": ".25em", // Opera 10.5 and IE9 + "-webkit-border-radius": ".25em", // Safari and Chrome + "-moz-border-radius": ".25em", // Firefox + "-khtml-border-radius": ".25em", // Konqueror + + "box-shadow": "0px 0px 15px #83A", // Opera 10.5 and IE9 + "-webkit-box-shadow": "0px 0px 15px #83A", // Safari and Chrome + "-moz-box-shadow": "0px 0px 15px #83A", // Forefox 3.5 + "-khtml-box-shadow": "0px 0px 15px #83A", // Konqueror + + border: ".1em solid #A6D ! important", + display: "inline-block", position:"absolute" + }, + ".MathJax_Hover_Arrow": { + position:"absolute", + top:"-5px", right:"-9px", + width:"15px", height:"11px", + cursor:"pointer" + }, "#MathJax_Tooltip": { position: "absolute", left: 0, top: 0, @@ -425,8 +446,8 @@ if (this.config.showMathMenu && (this.settings.context === "MathJax" || force)) { if (this.safariContextMenuBug) {setTimeout("window.getSelection().empty()",0)} if (this.msieEventBug) {event = window.event} - if (math.parentNode.className === "MathJax_Display") {math = math.parentNode} - return EVENT.ContextMenu(event,math); + this.ClearHoverTimer(); + return EVENT.ContextMenu(event,this.getJaxFromMath(math)); } }, Mousedown: function (event,math) { @@ -440,6 +461,105 @@ return this.ContextMenu(event,math,true); } }, + Mouseover: function (event,math) { + var from = event.fromElement || event.relatedTarget, + to = event.toElement || event.target; + if (from && to && from.isMathJax != to.isMathJax) { + var jax = this.getJaxFromMath(math); + if (jax.hover) {this.ReHover(jax)} else {this.HoverTimer(jax,math)} + return EVENT.False(event); + } + }, + Mouseout: function (event,math) { + var from = event.fromElement || event.relatedTarget, + to = event.toElement || event.target; + if (from && to && from.isMathJax != to.isMathJax) { + var jax = this.getJaxFromMath(math); + if (jax.hover) {this.UnHover(jax)} else {this.ClearHoverTimer()} + return EVENT.False(event); + } + }, + Mousemove: function (event,math) { + var jax = this.getJaxFromMath(math); if (jax.hover) return; + if (this.lastX == event.clientX && this.lastY == event.clientY) return; + this.lastX = event.clientX; this.lastY = event.clientY; + this.HoverTimer(jax,math); + return EVENT.False(event); + }, + + HoverTimer: function (jax,math) { + this.ClearHoverTimer(); + this.hoverTimer = setTimeout(MathJax.Callback(["Hover",this,jax,math]),this.settings.hover); + }, + ClearHoverTimer: function () { + if (this.hoverTimer) {clearTimeout(this.hoverTimer); delete this.hoverTimer} + }, + + Hover: function (jax,math) { + // check for MathZoom hover + jax.hover = {opacity:0}; + var span = jax.root.HTMLspanElement(), bbox = span.bbox; + var dx = .25, dy = .33, dd = .1; // frame size + if (this.msieBorderWidthBug) {dd = 0} + jax.hover.id = "MathJax-Hover-"+jax.inputID.replace(/.*-(\d+)$/,"$1"); + var frame = HTMLCSS.Element("span",{ + id:jax.hover.id, isMathJax: true, + style:{display:"inline-block", "z-index":1, width:0, height:0, position:"relative"} + },[["span",{ + className:"MathJax_Hover_Frame", isMathJax: true, + style:{ + display:"inline-block", position:"absolute", + top:HTMLCSS.Em(-bbox.h-dy-dd), left:HTMLCSS.Em(-dx-dd), + width:HTMLCSS.Em(bbox.w+2*dx), height:HTMLCSS.Em(bbox.h+bbox.d+2*dy), + opacity:0, filter:"alpha(opacity=0)" + }},[[ + "img",{ + className: "MathJax_Hover_Arrow", isMathJax: true, math: math, + src: AJAX.fileURL(MathJax.OutputJax.imageDir+"/MenuArrow-15.png"), + onclick: this.HoverMenu + } + ]] + ]] + ); + span.parentNode.insertBefore(frame,span); span.style.position = "relative"; + this.ReHover(jax,.2); + }, + ReHover: function (jax) { + if (jax.hover.remove) {clearTimeout(jax.hover.remove)} + jax.hover.remove = setTimeout(MathJax.Callback(["UnHover",this,jax]),15*1000); + this.HoverFadeTimer(jax,.2); + }, + UnHover: function (jax) { + if (!jax.hover.nofade) {this.HoverFadeTimer(jax,-.05,400)} + }, + HoverFade: function (jax) { + delete jax.hover.timer; + jax.hover.opacity = Math.max(0,Math.min(1,jax.hover.opacity + jax.hover.inc)); + jax.hover.opacity = Math.floor(1000*jax.hover.opacity)/1000; + var span = document.getElementById(jax.hover.id); + span.firstChild.style.opacity = jax.hover.opacity; + span.firstChild.style.filter = "alpha(opacity="+Math.floor(100*jax.hover.opacity)+")"; + if (jax.hover.opacity === 1) {return} + if (jax.hover.opacity) {this.HoverFadeTimer(jax,jax.hover.inc); return} + var frame = document.getElementById(jax.hover.id); + frame.parentNode.removeChild(frame); + if (jax.hover.remove) {clearTimeout(jax.hover.remove)} + delete jax.hover; + }, + HoverFadeTimer: function (jax,inc,delay) { + jax.hover.inc = inc; + if (!jax.hover.timer) { + jax.hover.timer = setTimeout(MathJax.Callback(["HoverFade",this,jax]),(delay||50)); + } + }, + HoverMenu: function (event) { + if (!event) {event = window.event} + HTMLCSS.ContextMenu(event,this.math,true); + }, + getJaxFromMath: function (math) { + if (math.parentNode.className === "MathJax_Display") {math = math.parentNode} + return HUB.getJaxFor(math.nextSibling); + }, initImg: function (span) {}, initHTML: function (math,span) {}, @@ -1284,7 +1404,7 @@ span.style.cssText = this.style; if (span.style.fontSize) {this.mathsize = span.style.fontSize; span.style.fontSize = ""} } - this.spanID = HTMLCSS.GetID(); + if (!this.spanID) {this.spanID = HTMLCSS.GetID()} span.id = (this.id || "MathJax-Span-"+this.spanID) + HTMLCSS.idPostfix; span.bbox = {w:0, h:0, d:0, lw:0, lr:0}; if (this.href) {span.parentNode.bbox = span.bbox} @@ -2103,7 +2223,8 @@ } } return span; - } + }, + HTMLspanElement: MML.mbase.prototype.HTMLspanElement }); MML.TeXAtom.Augment({ @@ -2141,6 +2262,13 @@ }); HUB.Register.StartupHook("End Config",function () { + + if (MathJax.Hub.Browser.isMobile) { + var arrow = HTMLCSS.config.styles[".MathJax_Hover_Arrow"]; + arrow.width = "25px"; arrow.height = "18px"; + arrow.top = "-11px"; arrow.right = "-15px"; + } + // // Handle browser-specific setup //