mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-11-03 19:17:02 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			532 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			532 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/*************************************************************
 | 
						|
 *
 | 
						|
 *  MathJax/extensions/MathEvents.js
 | 
						|
 *  
 | 
						|
 *  Implements the event handlers needed by the output jax to perform
 | 
						|
 *  menu, hover, and other events.
 | 
						|
 *
 | 
						|
 *  ---------------------------------------------------------------------
 | 
						|
 *  
 | 
						|
 *  Copyright (c) 2011-2012 Design Science, Inc.
 | 
						|
 * 
 | 
						|
 *  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,OUTPUT,INPUT) {
 | 
						|
  var VERSION = "2.0";
 | 
						|
  
 | 
						|
  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: -4, y: -3,          // menu button offsets
 | 
						|
      wx: -2,                // button offset for full-width equations
 | 
						|
      src: AJAX.fileURL(OUTPUT.imageDir+"/MenuArrow-15.png")  // button image
 | 
						|
    },
 | 
						|
    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_Hover_Arrow": {
 | 
						|
        position:"absolute",
 | 
						|
        width:"15px", height:"11px",
 | 
						|
        cursor:"pointer"
 | 
						|
      }
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  
 | 
						|
  //
 | 
						|
  //  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
 | 
						|
 | 
						|
    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()}
 | 
						|
        if (event.stopPropagation) {event.stopPropagation()}
 | 
						|
        event.cancelBubble = true;
 | 
						|
        event.returnValue = false;
 | 
						|
      }
 | 
						|
      return false;
 | 
						|
    },
 | 
						|
 | 
						|
    //
 | 
						|
    //  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, post the menu
 | 
						|
      //  Otherwse lad the menu code and try again
 | 
						|
      //
 | 
						|
      var MENU = MathJax.Menu;
 | 
						|
      if (MENU) {
 | 
						|
        MENU.jax = jax;
 | 
						|
        var source = MENU.menu.Find("Show Math As").menu;
 | 
						|
        source.items[1].name = (INPUT[jax.inputJax].sourceMenuTitle||"Original Form");
 | 
						|
        source.items[0].hidden = (jax.inputJax === "Error");  // hide MathML choice for error messages
 | 
						|
        var MathPlayer = MENU.menu.Find("Math Settings","MathPlayer");
 | 
						|
        MathPlayer.hidden = !(jax.outputJax === "NativeMML" && HUB.Browser.hasMathPlayer);
 | 
						|
        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
 | 
						|
          };
 | 
						|
          CALLBACK.Queue(
 | 
						|
            AJAX.Require("[MathJax]/extensions/MathMenu.js"),
 | 
						|
            function () {delete AJAX.loadingMathMenu; if (!MathJax.Menu) {MathJax.Menu = {}}},
 | 
						|
            ["ContextMenu",this,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 && (from.isMathJax != to.isMathJax ||
 | 
						|
                           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 && (from.isMathJax != to.isMathJax ||
 | 
						|
                           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",
 | 
						|
         style:{display:"inline-block", "z-index": 1, width:0, height:0, position:"relative"}
 | 
						|
        },[["img",{
 | 
						|
            className: "MathJax_Hover_Arrow", isMathJax: true, math: math,
 | 
						|
            src: CONFIG.button.src, 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)"
 | 
						|
            }
 | 
						|
          }]]
 | 
						|
      );
 | 
						|
      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 () {
 | 
						|
      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.last = now;
 | 
						|
      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) {
 | 
						|
      if (TOUCH.timeout) {
 | 
						|
        clearTimeout(TOUCH.timeout);
 | 
						|
        delete TOUCH.timeout; TOUCH.last = 0;
 | 
						|
        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;
 | 
						|
      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.OutputJax,MathJax.InputJax);
 |