You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
620 lines
22 KiB
620 lines
22 KiB
5 years ago
|
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
|
||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||
|
|
||
|
/*************************************************************
|
||
|
*
|
||
|
* MathJax/extensions/MathEvents.js
|
||
|
*
|
||
|
* Implements the event handlers needed by the output jax to perform
|
||
|
* menu, hover, and other events.
|
||
|
*
|
||
|
* ---------------------------------------------------------------------
|
||
|
*
|
||
|
* Copyright (c) 2011-2018 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,CALLBACK,LOCALE,OUTPUT,INPUT) {
|
||
|
var VERSION = "2.7.5";
|
||
|
|
||
|
var EXTENSION = MathJax.Extension;
|
||
|
var ME = EXTENSION.MathEvents = {version: VERSION};
|
||
|
|
||
|
var SETTINGS = HUB.config.menuSettings;
|
||
|
|
||
|
var CONFIG = {
|
||
|
hover: 500, // time required to be considered a hover
|
||
|
frame: {
|
||
|
x: 3.5, y: 5, // frame padding and
|
||
|
bwidth: 1, // frame border width (in pixels)
|
||
|
bcolor: "#A6D", // frame border color
|
||
|
hwidth: "15px", // haze width
|
||
|
hcolor: "#83A" // haze color
|
||
|
},
|
||
|
button: {
|
||
|
x: -6, y: -3, // menu button offsets
|
||
|
wx: -2 // button offset for full-width equations
|
||
|
},
|
||
|
fadeinInc: .2, // increment for fade-in
|
||
|
fadeoutInc: .05, // increment for fade-out
|
||
|
fadeDelay: 50, // delay between fade-in or fade-out steps
|
||
|
fadeoutStart: 400, // delay before fade-out after mouseout
|
||
|
fadeoutDelay: 15*1000, // delay before automatic fade-out
|
||
|
|
||
|
styles: {
|
||
|
".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
|
||
|
"-khtml-box-shadow": "0px 0px 15px #83A", // Konqueror
|
||
|
|
||
|
border: "1px solid #A6D ! important",
|
||
|
display: "inline-block", position:"absolute"
|
||
|
},
|
||
|
|
||
|
".MathJax_Menu_Button .MathJax_Hover_Arrow": {
|
||
|
position:"absolute",
|
||
|
cursor:"pointer",
|
||
|
display:"inline-block",
|
||
|
border:"2px solid #AAA",
|
||
|
"border-radius":"4px",
|
||
|
"-webkit-border-radius": "4px", // Safari and Chrome
|
||
|
"-moz-border-radius": "4px", // Firefox
|
||
|
"-khtml-border-radius": "4px", // Konqueror
|
||
|
"font-family":"'Courier New',Courier",
|
||
|
"font-size":"9px",
|
||
|
color:"#F0F0F0"
|
||
|
},
|
||
|
".MathJax_Menu_Button .MathJax_Hover_Arrow span": {
|
||
|
display:"block",
|
||
|
"background-color":"#AAA",
|
||
|
border:"1px solid",
|
||
|
"border-radius":"3px",
|
||
|
"line-height":0,
|
||
|
padding:"4px"
|
||
|
},
|
||
|
".MathJax_Hover_Arrow:hover": {
|
||
|
color:"white!important",
|
||
|
border:"2px solid #CCC!important"
|
||
|
},
|
||
|
".MathJax_Hover_Arrow:hover span": {
|
||
|
"background-color":"#CCC!important"
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
//
|
||
|
// Common event-handling code
|
||
|
//
|
||
|
var EVENT = ME.Event = {
|
||
|
|
||
|
LEFTBUTTON: 0, // the event.button value for left button
|
||
|
RIGHTBUTTON: 2, // the event.button value for right button
|
||
|
MENUKEY: "altKey", // the event value for alternate context menu
|
||
|
|
||
|
/*************************************************************/
|
||
|
/*
|
||
|
* Enum element for key codes.
|
||
|
*/
|
||
|
KEY: {
|
||
|
RETURN: 13,
|
||
|
ESCAPE: 27,
|
||
|
SPACE: 32,
|
||
|
LEFT: 37,
|
||
|
UP: 38,
|
||
|
RIGHT: 39,
|
||
|
DOWN: 40
|
||
|
},
|
||
|
|
||
|
Mousedown: function (event) {return EVENT.Handler(event,"Mousedown",this)},
|
||
|
Mouseup: function (event) {return EVENT.Handler(event,"Mouseup",this)},
|
||
|
Mousemove: function (event) {return EVENT.Handler(event,"Mousemove",this)},
|
||
|
Mouseover: function (event) {return EVENT.Handler(event,"Mouseover",this)},
|
||
|
Mouseout: function (event) {return EVENT.Handler(event,"Mouseout",this)},
|
||
|
Click: function (event) {return EVENT.Handler(event,"Click",this)},
|
||
|
DblClick: function (event) {return EVENT.Handler(event,"DblClick",this)},
|
||
|
Menu: function (event) {return EVENT.Handler(event,"ContextMenu",this)},
|
||
|
|
||
|
//
|
||
|
// Call the output jax's event handler or the zoom handler
|
||
|
//
|
||
|
Handler: function (event,type,math) {
|
||
|
if (AJAX.loadingMathMenu) {return EVENT.False(event)}
|
||
|
var jax = OUTPUT[math.jaxID];
|
||
|
if (!event) {event = window.event}
|
||
|
event.isContextMenu = (type === "ContextMenu");
|
||
|
if (jax[type]) {return jax[type](event,math)}
|
||
|
if (EXTENSION.MathZoom) {return EXTENSION.MathZoom.HandleEvent(event,type,math)}
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// Try to cancel the event in every way we can
|
||
|
//
|
||
|
False: function (event) {
|
||
|
if (!event) {event = window.event}
|
||
|
if (event) {
|
||
|
if (event.preventDefault) {event.preventDefault()} else {event.returnValue = false}
|
||
|
if (event.stopPropagation) {event.stopPropagation()}
|
||
|
event.cancelBubble = true;
|
||
|
}
|
||
|
return false;
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// Keydown event handler. Should only fire on Space key.
|
||
|
//
|
||
|
Keydown: function (event, math) {
|
||
|
if (!event) event = window.event;
|
||
|
if (event.keyCode === EVENT.KEY.SPACE) {
|
||
|
EVENT.ContextMenu(event, this);
|
||
|
};
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// Load the contextual menu code, if needed, and post the menu
|
||
|
//
|
||
|
ContextMenu: function (event,math,force) {
|
||
|
//
|
||
|
// Check if we are showing menus
|
||
|
//
|
||
|
var JAX = OUTPUT[math.jaxID], jax = JAX.getJaxFromMath(math);
|
||
|
var show = (JAX.config.showMathMenu != null ? JAX : HUB).config.showMathMenu;
|
||
|
if (!show || (SETTINGS.context !== "MathJax" && !force)) return;
|
||
|
|
||
|
//
|
||
|
// Remove selections, remove hover fades
|
||
|
//
|
||
|
if (ME.msieEventBug) {event = window.event || event}
|
||
|
EVENT.ClearSelection(); HOVER.ClearHoverTimer();
|
||
|
if (jax.hover) {
|
||
|
if (jax.hover.remove) {clearTimeout(jax.hover.remove); delete jax.hover.remove}
|
||
|
jax.hover.nofade = true;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the menu code is loaded,
|
||
|
// Check if localization needs loading;
|
||
|
// If not, post the menu, and return.
|
||
|
// Otherwise wait for the localization to load
|
||
|
// Otherwse load the menu code.
|
||
|
// Try again after the file is loaded.
|
||
|
//
|
||
|
var MENU = MathJax.Menu; var load, fn;
|
||
|
if (MENU) {
|
||
|
if (MENU.loadingDomain) {return EVENT.False(event)}
|
||
|
load = LOCALE.loadDomain("MathMenu");
|
||
|
if (!load) {
|
||
|
MENU.jax = jax;
|
||
|
var source = MENU.menu.Find("Show Math As").submenu;
|
||
|
source.items[0].name = jax.sourceMenuTitle;
|
||
|
source.items[0].format = (jax.sourceMenuFormat||"MathML");
|
||
|
source.items[1].name = INPUT[jax.inputJax].sourceMenuTitle;
|
||
|
source.items[5].disabled = !INPUT[jax.inputJax].annotationEncoding;
|
||
|
|
||
|
//
|
||
|
// Try and find each known annotation format and enable the menu
|
||
|
// items accordingly.
|
||
|
//
|
||
|
var annotations = source.items[2]; annotations.disabled = true;
|
||
|
var annotationItems = annotations.submenu.items;
|
||
|
annotationList = MathJax.Hub.Config.semanticsAnnotations;
|
||
|
for (var i = 0, m = annotationItems.length; i < m; i++) {
|
||
|
var name = annotationItems[i].name[1]
|
||
|
if (jax.root && jax.root.getAnnotation(name) !== null) {
|
||
|
annotations.disabled = false;
|
||
|
annotationItems[i].hidden = false;
|
||
|
} else {
|
||
|
annotationItems[i].hidden = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var MathPlayer = MENU.menu.Find("Math Settings","MathPlayer");
|
||
|
MathPlayer.hidden = !(jax.outputJax === "NativeMML" && HUB.Browser.hasMathPlayer);
|
||
|
return MENU.menu.Post(event);
|
||
|
}
|
||
|
MENU.loadingDomain = true;
|
||
|
fn = function () {delete MENU.loadingDomain};
|
||
|
} else {
|
||
|
if (AJAX.loadingMathMenu) {return EVENT.False(event)}
|
||
|
AJAX.loadingMathMenu = true;
|
||
|
load = AJAX.Require("[MathJax]/extensions/MathMenu.js");
|
||
|
fn = function () {
|
||
|
delete AJAX.loadingMathMenu;
|
||
|
if (!MathJax.Menu) {MathJax.Menu = {}}
|
||
|
}
|
||
|
}
|
||
|
var ev = {
|
||
|
pageX:event.pageX, pageY:event.pageY,
|
||
|
clientX:event.clientX, clientY:event.clientY
|
||
|
};
|
||
|
CALLBACK.Queue(
|
||
|
load, fn, // load the file and delete the marker when done
|
||
|
["ContextMenu",EVENT,ev,math,force] // call this function again
|
||
|
);
|
||
|
return EVENT.False(event);
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// Mousedown handler for alternate means of accessing menu
|
||
|
//
|
||
|
AltContextMenu: function (event,math) {
|
||
|
var JAX = OUTPUT[math.jaxID];
|
||
|
var show = (JAX.config.showMathMenu != null ? JAX : HUB).config.showMathMenu;
|
||
|
if (show) {
|
||
|
show = (JAX.config.showMathMenuMSIE != null ? JAX : HUB).config.showMathMenuMSIE;
|
||
|
if (SETTINGS.context === "MathJax" && !SETTINGS.mpContext && show) {
|
||
|
if (!ME.noContextMenuBug || event.button !== EVENT.RIGHTBUTTON) return;
|
||
|
} else {
|
||
|
if (!event[EVENT.MENUKEY] || event.button !== EVENT.LEFTBUTTON) return;
|
||
|
}
|
||
|
return JAX.ContextMenu(event,math,true);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
ClearSelection: function () {
|
||
|
if (ME.safariContextMenuBug) {setTimeout("window.getSelection().empty()",0)}
|
||
|
if (document.selection) {setTimeout("document.selection.empty()",0)}
|
||
|
},
|
||
|
|
||
|
getBBox: function (span) {
|
||
|
span.appendChild(ME.topImg);
|
||
|
var h = ME.topImg.offsetTop, d = span.offsetHeight-h, w = span.offsetWidth;
|
||
|
span.removeChild(ME.topImg);
|
||
|
return {w:w, h:h, d:d};
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Handle hover "discoverability"
|
||
|
//
|
||
|
var HOVER = ME.Hover = {
|
||
|
|
||
|
//
|
||
|
// Check if we are moving from a non-MathJax element to a MathJax one
|
||
|
// and either start fading in again (if it is fading out) or start the
|
||
|
// timer for the hover
|
||
|
//
|
||
|
Mouseover: function (event,math) {
|
||
|
if (SETTINGS.discoverable || SETTINGS.zoom === "Hover") {
|
||
|
var from = event.fromElement || event.relatedTarget,
|
||
|
to = event.toElement || event.target;
|
||
|
if (from && to && (HUB.isMathJaxNode(from) !== HUB.isMathJaxNode(to) ||
|
||
|
HUB.getJaxFor(from) !== HUB.getJaxFor(to))) {
|
||
|
var jax = this.getJaxFromMath(math);
|
||
|
if (jax.hover) {HOVER.ReHover(jax)} else {HOVER.HoverTimer(jax,math)}
|
||
|
return EVENT.False(event);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
//
|
||
|
// Check if we are moving from a MathJax element to a non-MathJax one
|
||
|
// and either start fading out, or clear the timer if we haven't
|
||
|
// hovered yet
|
||
|
//
|
||
|
Mouseout: function (event,math) {
|
||
|
if (SETTINGS.discoverable || SETTINGS.zoom === "Hover") {
|
||
|
var from = event.fromElement || event.relatedTarget,
|
||
|
to = event.toElement || event.target;
|
||
|
if (from && to && (HUB.isMathJaxNode(from) !== HUB.isMathJaxNode(to) ||
|
||
|
HUB.getJaxFor(from) !== HUB.getJaxFor(to))) {
|
||
|
var jax = this.getJaxFromMath(math);
|
||
|
if (jax.hover) {HOVER.UnHover(jax)} else {HOVER.ClearHoverTimer()}
|
||
|
return EVENT.False(event);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
//
|
||
|
// Restart hover timer if the mouse moves
|
||
|
//
|
||
|
Mousemove: function (event,math) {
|
||
|
if (SETTINGS.discoverable || SETTINGS.zoom === "Hover") {
|
||
|
var jax = this.getJaxFromMath(math); if (jax.hover) return;
|
||
|
if (HOVER.lastX == event.clientX && HOVER.lastY == event.clientY) return;
|
||
|
HOVER.lastX = event.clientX; HOVER.lastY = event.clientY;
|
||
|
HOVER.HoverTimer(jax,math);
|
||
|
return EVENT.False(event);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// Clear the old timer and start a new one
|
||
|
//
|
||
|
HoverTimer: function (jax,math) {
|
||
|
this.ClearHoverTimer();
|
||
|
this.hoverTimer = setTimeout(CALLBACK(["Hover",this,jax,math]),CONFIG.hover);
|
||
|
},
|
||
|
ClearHoverTimer: function () {
|
||
|
if (this.hoverTimer) {clearTimeout(this.hoverTimer); delete this.hoverTimer}
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// Handle putting up the hover frame
|
||
|
//
|
||
|
Hover: function (jax,math) {
|
||
|
//
|
||
|
// Check if Zoom handles the hover event
|
||
|
//
|
||
|
if (EXTENSION.MathZoom && EXTENSION.MathZoom.Hover({},math)) return;
|
||
|
//
|
||
|
// Get the hover data
|
||
|
//
|
||
|
var JAX = OUTPUT[jax.outputJax],
|
||
|
span = JAX.getHoverSpan(jax,math),
|
||
|
bbox = JAX.getHoverBBox(jax,span,math),
|
||
|
show = (JAX.config.showMathMenu != null ? JAX : HUB).config.showMathMenu;
|
||
|
var dx = CONFIG.frame.x, dy = CONFIG.frame.y, dd = CONFIG.frame.bwidth; // frame size
|
||
|
if (ME.msieBorderWidthBug) {dd = 0}
|
||
|
jax.hover = {opacity:0, id:jax.inputID+"-Hover"};
|
||
|
//
|
||
|
// The frame and menu button
|
||
|
//
|
||
|
var frame = HTML.Element("span",{
|
||
|
id:jax.hover.id, isMathJax: true,
|
||
|
style:{display:"inline-block", width:0, height:0, position:"relative"}
|
||
|
},[["span",{
|
||
|
className:"MathJax_Hover_Frame", isMathJax: true,
|
||
|
style:{
|
||
|
display:"inline-block", position:"absolute",
|
||
|
top:this.Px(-bbox.h-dy-dd-(bbox.y||0)), left:this.Px(-dx-dd+(bbox.x||0)),
|
||
|
width:this.Px(bbox.w+2*dx), height:this.Px(bbox.h+bbox.d+2*dy),
|
||
|
opacity:0, filter:"alpha(opacity=0)"
|
||
|
}}
|
||
|
]]
|
||
|
);
|
||
|
var button = HTML.Element("span",{
|
||
|
isMathJax: true, id:jax.hover.id+"Menu", className:"MathJax_Menu_Button",
|
||
|
style:{display:"inline-block", "z-index": 1, width:0, height:0, position:"relative"}
|
||
|
},[["span",{
|
||
|
className: "MathJax_Hover_Arrow", isMathJax: true, math: math,
|
||
|
onclick: this.HoverMenu, jax:JAX.id,
|
||
|
style: {
|
||
|
left:this.Px(bbox.w+dx+dd+(bbox.x||0)+CONFIG.button.x),
|
||
|
top:this.Px(-bbox.h-dy-dd-(bbox.y||0)-CONFIG.button.y),
|
||
|
opacity:0, filter:"alpha(opacity=0)"
|
||
|
}
|
||
|
},[["span",{isMathJax:true},"\u25BC"]]]]
|
||
|
);
|
||
|
if (bbox.width) {
|
||
|
frame.style.width = button.style.width = bbox.width;
|
||
|
frame.style.marginRight = button.style.marginRight = "-"+bbox.width;
|
||
|
frame.firstChild.style.width = bbox.width;
|
||
|
button.firstChild.style.left = "";
|
||
|
button.firstChild.style.right = this.Px(CONFIG.button.wx);
|
||
|
}
|
||
|
//
|
||
|
// Add the frame and button
|
||
|
//
|
||
|
span.parentNode.insertBefore(frame,span);
|
||
|
if (show) {span.parentNode.insertBefore(button,span)}
|
||
|
if (span.style) {span.style.position = "relative"} // so math is on top of hover frame
|
||
|
//
|
||
|
// Start the hover fade-in
|
||
|
//
|
||
|
this.ReHover(jax);
|
||
|
},
|
||
|
//
|
||
|
// Restart the hover fade in and fade-out timers
|
||
|
//
|
||
|
ReHover: function (jax) {
|
||
|
if (jax.hover.remove) {clearTimeout(jax.hover.remove)}
|
||
|
jax.hover.remove = setTimeout(CALLBACK(["UnHover",this,jax]),CONFIG.fadeoutDelay);
|
||
|
this.HoverFadeTimer(jax,CONFIG.fadeinInc);
|
||
|
},
|
||
|
//
|
||
|
// Start the fade-out
|
||
|
//
|
||
|
UnHover: function (jax) {
|
||
|
if (!jax.hover.nofade) {this.HoverFadeTimer(jax,-CONFIG.fadeoutInc,CONFIG.fadeoutStart)}
|
||
|
},
|
||
|
//
|
||
|
// Handle the fade-in and fade-out
|
||
|
//
|
||
|
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 frame = document.getElementById(jax.hover.id),
|
||
|
button = document.getElementById(jax.hover.id+"Menu");
|
||
|
frame.firstChild.style.opacity = jax.hover.opacity;
|
||
|
frame.firstChild.style.filter = "alpha(opacity="+Math.floor(100*jax.hover.opacity)+")";
|
||
|
if (button) {
|
||
|
button.firstChild.style.opacity = jax.hover.opacity;
|
||
|
button.firstChild.style.filter = frame.style.filter;
|
||
|
}
|
||
|
if (jax.hover.opacity === 1) {return}
|
||
|
if (jax.hover.opacity > 0) {this.HoverFadeTimer(jax,jax.hover.inc); return}
|
||
|
frame.parentNode.removeChild(frame);
|
||
|
if (button) {button.parentNode.removeChild(button)}
|
||
|
if (jax.hover.remove) {clearTimeout(jax.hover.remove)}
|
||
|
delete jax.hover;
|
||
|
},
|
||
|
//
|
||
|
// Set the fade to in or out (via inc) and start the timer, if needed
|
||
|
//
|
||
|
HoverFadeTimer: function (jax,inc,delay) {
|
||
|
jax.hover.inc = inc;
|
||
|
if (!jax.hover.timer) {
|
||
|
jax.hover.timer = setTimeout(CALLBACK(["HoverFade",this,jax]),(delay||CONFIG.fadeDelay));
|
||
|
}
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// Handle a click on the menu button
|
||
|
//
|
||
|
HoverMenu: function (event) {
|
||
|
if (!event) {event = window.event}
|
||
|
return OUTPUT[this.jax].ContextMenu(event,this.math,true);
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// Clear all hover timers
|
||
|
//
|
||
|
ClearHover: function (jax) {
|
||
|
if (jax.hover.remove) {clearTimeout(jax.hover.remove)}
|
||
|
if (jax.hover.timer) {clearTimeout(jax.hover.timer)}
|
||
|
HOVER.ClearHoverTimer();
|
||
|
delete jax.hover;
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// Make a measurement in pixels
|
||
|
//
|
||
|
Px: function (m) {
|
||
|
if (Math.abs(m) < .006) {return "0px"}
|
||
|
return m.toFixed(2).replace(/\.?0+$/,"") + "px";
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// Preload images so they show up with the menu
|
||
|
//
|
||
|
getImages: function () {
|
||
|
if (SETTINGS.discoverable) {
|
||
|
var menu = new Image();
|
||
|
menu.src = CONFIG.button.src;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Handle touch events.
|
||
|
//
|
||
|
// Use double-tap-and-hold as a replacement for context menu event.
|
||
|
// Use double-tap as a replacement for double click.
|
||
|
//
|
||
|
var TOUCH = ME.Touch = {
|
||
|
|
||
|
last: 0, // time of last tap event
|
||
|
delay: 500, // delay time for double-click
|
||
|
|
||
|
//
|
||
|
// Check if this is a double-tap, and if so, start the timer
|
||
|
// for the double-tap and hold (to trigger the contextual menu)
|
||
|
//
|
||
|
start: function (event) {
|
||
|
var now = new Date().getTime();
|
||
|
var dblTap = (now - TOUCH.last < TOUCH.delay && TOUCH.up);
|
||
|
TOUCH.last = now; TOUCH.up = false;
|
||
|
if (dblTap) {
|
||
|
TOUCH.timeout = setTimeout(TOUCH.menu,TOUCH.delay,event,this);
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// Check if there is a timeout pending, i.e., we have a
|
||
|
// double-tap and were waiting to see if it is held long
|
||
|
// enough for the menu. Since we got the end before the
|
||
|
// timeout, it is a double-click, not a double-tap-and-hold.
|
||
|
// Prevent the default action and issue a double click.
|
||
|
//
|
||
|
end: function (event) {
|
||
|
var now = new Date().getTime();
|
||
|
TOUCH.up = (now - TOUCH.last < TOUCH.delay);
|
||
|
if (TOUCH.timeout) {
|
||
|
clearTimeout(TOUCH.timeout);
|
||
|
delete TOUCH.timeout; TOUCH.last = 0; TOUCH.up = false;
|
||
|
event.preventDefault();
|
||
|
return EVENT.Handler((event.touches[0]||event.touch),"DblClick",this);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// If the timeout passes without an end event, we issue
|
||
|
// the contextual menu event.
|
||
|
//
|
||
|
menu: function (event,math) {
|
||
|
delete TOUCH.timeout; TOUCH.last = 0; TOUCH.up = false;
|
||
|
return EVENT.Handler((event.touches[0]||event.touch),"ContextMenu",math);
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* //
|
||
|
* // Mobile screens are small, so use larger version of arrow
|
||
|
* //
|
||
|
* if (HUB.Browser.isMobile) {
|
||
|
* var arrow = CONFIG.styles[".MathJax_Hover_Arrow"];
|
||
|
* arrow.width = "25px"; arrow.height = "18px";
|
||
|
* CONFIG.button.x = -6;
|
||
|
* }
|
||
|
*/
|
||
|
|
||
|
//
|
||
|
// Set up browser-specific values
|
||
|
//
|
||
|
HUB.Browser.Select({
|
||
|
MSIE: function (browser) {
|
||
|
var mode = (document.documentMode || 0);
|
||
|
var isIE8 = browser.versionAtLeast("8.0");
|
||
|
ME.msieBorderWidthBug = (document.compatMode === "BackCompat"); // borders are inside offsetWidth/Height
|
||
|
ME.msieEventBug = browser.isIE9; // must get event from window even though event is passed
|
||
|
ME.msieAlignBug = (!isIE8 || mode < 8); // inline-block spans don't rest on baseline
|
||
|
if (mode < 9) {EVENT.LEFTBUTTON = 1} // IE < 9 has wrong event.button values
|
||
|
},
|
||
|
Safari: function (browser) {
|
||
|
ME.safariContextMenuBug = true; // selection can be started by contextmenu event
|
||
|
},
|
||
|
Opera: function (browser) {
|
||
|
ME.operaPositionBug = true; // position is wrong unless border is used
|
||
|
},
|
||
|
Konqueror: function (browser) {
|
||
|
ME.noContextMenuBug = true; // doesn't produce contextmenu event
|
||
|
}
|
||
|
});
|
||
|
|
||
|
//
|
||
|
// Used in measuring zoom and hover positions
|
||
|
//
|
||
|
ME.topImg = (ME.msieAlignBug ?
|
||
|
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 (ME.operaPositionBug) {ME.topImg.style.border="1px solid"}
|
||
|
|
||
|
//
|
||
|
// Get configuration from user
|
||
|
//
|
||
|
ME.config = CONFIG = HUB.CombineConfig("MathEvents",CONFIG);
|
||
|
var SETFRAME = function () {
|
||
|
var haze = CONFIG.styles[".MathJax_Hover_Frame"];
|
||
|
haze.border = CONFIG.frame.bwidth+"px solid "+CONFIG.frame.bcolor+" ! important";
|
||
|
haze["box-shadow"] = haze["-webkit-box-shadow"] =
|
||
|
haze["-moz-box-shadow"] = haze["-khtml-box-shadow"] =
|
||
|
"0px 0px "+CONFIG.frame.hwidth+" "+CONFIG.frame.hcolor;
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Queue the events needed for startup
|
||
|
//
|
||
|
CALLBACK.Queue(
|
||
|
HUB.Register.StartupHook("End Config",{}), // wait until config is complete
|
||
|
[SETFRAME],
|
||
|
["getImages",HOVER],
|
||
|
["Styles",AJAX,CONFIG.styles],
|
||
|
["Post",HUB.Startup.signal,"MathEvents Ready"],
|
||
|
["loadComplete",AJAX,"[MathJax]/extensions/MathEvents.js"]
|
||
|
);
|
||
|
|
||
|
})(MathJax.Hub,MathJax.HTML,MathJax.Ajax,MathJax.Callback,
|
||
|
MathJax.Localization,MathJax.OutputJax,MathJax.InputJax);
|