Add touch event support for mobile devices so they can access the menus (still need to work on Firefox support, but works for WebKit-based mobiles)

This commit is contained in:
Davide P. Cervone 2011-08-14 20:17:42 -04:00
parent da8d4885fb
commit 816d2cbcfd
18 changed files with 207 additions and 66 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -12,5 +12,5 @@
* http://www.apache.org/licenses/LICENSE-2.0
*/
MathJax.OutputJax["HTML-CSS"]=MathJax.OutputJax({id:"HTML-CSS",version:"1.1.5",directory:MathJax.OutputJax.directory+"/HTML-CSS",extensionDir:MathJax.OutputJax.extensionDir+"/HTML-CSS",autoloadDir:MathJax.OutputJax.directory+"/HTML-CSS/autoload",fontDir:MathJax.OutputJax.directory+"/HTML-CSS/fonts",webfontDir:MathJax.OutputJax.fontDir+"/HTML-CSS",config:{scale:100,minScaleAdjust:50,availableFonts:["STIX","TeX"],preferredFont:"TeX",webFont:"TeX",imageFont:"TeX",undefinedFamily:"STIXGeneral,'Arial Unicode MS',serif",showMathMenu:true,styles:{".MathJax_Display":{"text-align":"center",margin:"1em 0em"},".MathJax .merror":{"background-color":"#FFFF88",color:"#CC0000",border:"1px solid #CC0000",padding:"1px 3px","font-family":"serif","font-style":"normal","font-size":"90%"},".MathJax_Preview":{color:"#888888"},"#MathJax_Tooltip":{"background-color":"InfoBackground",color:"InfoText",border:"1px solid black","box-shadow":"2px 2px 5px #AAAAAA","-webkit-box-shadow":"2px 2px 5px #AAAAAA","-moz-box-shadow":"2px 2px 5px #AAAAAA","-khtml-box-shadow":"2px 2px 5px #AAAAAA",filter:"progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')",padding:"3px 4px"}}}});if(MathJax.Hub.Browser.isMSIE&&document.documentMode>=9){delete MathJax.OutputJax["HTML-CSS"].config.styles["#MathJax_Tooltip"].filter}if(!MathJax.Hub.config.delayJaxRegistration){MathJax.OutputJax["HTML-CSS"].Register("jax/mml")}MathJax.Hub.Register.StartupHook("End Config",[function(b,c){var a=b.Insert({minBrowserVersion:{Firefox:3,Opera:9.52,MSIE:6,Chrome:0.3,Safari:2,Konqueror:4},inlineMathDelimiters:["$","$"],displayMathDelimiters:["$$","$$"],multilineDisplay:true,minBrowserTranslate:function(f){var e=b.getJaxFor(f),k=["[Math]"],j;var h=document.createElement("span",{className:"MathJax_Preview"});if(e.inputJax.id==="TeX"){if(e.root.Get("displaystyle")){j=a.displayMathDelimiters;k=[j[0]+e.originalText+j[1]];if(a.multilineDisplay){k=k[0].split(/\n/)}}else{j=a.inlineMathDelimiters;k=[j[0]+e.originalText.replace(/^\s+/,"").replace(/\s+$/,"")+j[1]]}}for(var g=0,d=k.length;g<d;g++){h.appendChild(document.createTextNode(k[g]));if(g<d-1){h.appendChild(document.createElement("br"))}}f.parentNode.insertBefore(h,f)}},(b.config["HTML-CSS"]||{}));if(b.Browser.version!=="0.0"&&!b.Browser.versionAtLeast(a.minBrowserVersion[b.Browser]||0)){c.Translate=a.minBrowserTranslate;b.Config({showProcessingMessages:false});MathJax.Message.Set("Your browser does not support MathJax",null,4000);b.Startup.signal.Post("MathJax not supported")}},MathJax.Hub,MathJax.OutputJax["HTML-CSS"]]);MathJax.OutputJax["HTML-CSS"].loadComplete("config.js");
MathJax.OutputJax["HTML-CSS"]=MathJax.OutputJax({id:"HTML-CSS",version:"1.1.6",directory:MathJax.OutputJax.directory+"/HTML-CSS",extensionDir:MathJax.OutputJax.extensionDir+"/HTML-CSS",autoloadDir:MathJax.OutputJax.directory+"/HTML-CSS/autoload",fontDir:MathJax.OutputJax.directory+"/HTML-CSS/fonts",webfontDir:MathJax.OutputJax.fontDir+"/HTML-CSS",config:{scale:100,minScaleAdjust:50,availableFonts:["STIX","TeX"],preferredFont:"TeX",webFont:"TeX",imageFont:"TeX",undefinedFamily:"STIXGeneral,'Arial Unicode MS',serif",showMathMenu:true,styles:{".MathJax_Display":{"text-align":"center",margin:"1em 0em"},".MathJax .merror":{"background-color":"#FFFF88",color:"#CC0000",border:"1px solid #CC0000",padding:"1px 3px","font-family":"serif","font-style":"normal","font-size":"90%"},".MathJax_Preview":{color:"#888888"},"#MathJax_Tooltip":{"background-color":"InfoBackground",color:"InfoText",border:"1px solid black","box-shadow":"2px 2px 5px #AAAAAA","-webkit-box-shadow":"2px 2px 5px #AAAAAA","-moz-box-shadow":"2px 2px 5px #AAAAAA","-khtml-box-shadow":"2px 2px 5px #AAAAAA",filter:"progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')",padding:"3px 4px"}}}});if(MathJax.Hub.Browser.isMSIE&&document.documentMode>=9){delete MathJax.OutputJax["HTML-CSS"].config.styles["#MathJax_Tooltip"].filter}if(!MathJax.Hub.config.delayJaxRegistration){MathJax.OutputJax["HTML-CSS"].Register("jax/mml")}MathJax.Hub.Register.StartupHook("End Config",[function(b,c){var a=b.Insert({minBrowserVersion:{Firefox:3,Opera:9.52,MSIE:6,Chrome:0.3,Safari:2,Konqueror:4},inlineMathDelimiters:["$","$"],displayMathDelimiters:["$$","$$"],multilineDisplay:true,minBrowserTranslate:function(f){var e=b.getJaxFor(f),k=["[Math]"],j;var h=document.createElement("span",{className:"MathJax_Preview"});if(e.inputJax.id==="TeX"){if(e.root.Get("displaystyle")){j=a.displayMathDelimiters;k=[j[0]+e.originalText+j[1]];if(a.multilineDisplay){k=k[0].split(/\n/)}}else{j=a.inlineMathDelimiters;k=[j[0]+e.originalText.replace(/^\s+/,"").replace(/\s+$/,"")+j[1]]}}for(var g=0,d=k.length;g<d;g++){h.appendChild(document.createTextNode(k[g]));if(g<d-1){h.appendChild(document.createElement("br"))}}f.parentNode.insertBefore(h,f)}},(b.config["HTML-CSS"]||{}));if(b.Browser.version!=="0.0"&&!b.Browser.versionAtLeast(a.minBrowserVersion[b.Browser]||0)){c.Translate=a.minBrowserTranslate;b.Config({showProcessingMessages:false});MathJax.Message.Set("Your browser does not support MathJax",null,4000);b.Startup.signal.Post("MathJax not supported")}},MathJax.Hub,MathJax.OutputJax["HTML-CSS"]]);MathJax.OutputJax["HTML-CSS"].loadComplete("config.js");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -30,7 +30,7 @@ if (!window.MathJax) {window.MathJax= {}}
if (!MathJax.Hub) { // skip if already loaded
MathJax.version = "1.1a";
MathJax.fileversion = "1.1.7";
MathJax.fileversion = "1.1.8";
/**********************************************************/
@ -2050,6 +2050,8 @@ MathJax.Hub.Startup = {
else if (v > 500) {browser.version = "3.0"}
else if (v > 400) {browser.version = "2.0"}
else if (v > 85) {browser.version = "1.0"}
browser.isMobile = (navigator.appVersion.match(/Mobile/i) != null);
browser.noContextMenu = browser.isMobile;
},
Firefox: function (browser) {
if (browser.version === "0.0" && navigator.product === "Gecko" && navigator.productSub) {
@ -2058,6 +2060,8 @@ MathJax.Hub.Startup = {
else if (date >= "20080617") {browser.version = "3.0"}
else if (date >= "20061024") {browser.version = "2.0"}
}
browser.isMobile = (navigator.appVersion.match(/Android/i) != null ||
navigator.userAgent.match(/ Fennec\//) != null);
},
Opera: function (browser) {browser.version = opera.version()},
MSIE: function (browser) {

View File

@ -24,7 +24,7 @@
*/
(function (HUB,HTML,AJAX) {
var VERSION = "1.1.4";
var VERSION = "1.1.5";
MathJax.Extension.MathMenu = {version: VERSION};
@ -148,7 +148,7 @@
}
return false;
};
/*************************************************************/
/*
* The main menu class
@ -170,7 +170,11 @@
if (!event) {event = window.event};
var title = (!this.title ? null : [["div",{className: "MathJax_MenuTitle"},[this.title]]]);
var div = document.getElementById("MathJax_MenuFrame");
if (!div) {div = MENU.Background(this)}
if (!div) {
div = MENU.Background(this);
delete ITEM.lastItem; delete ITEM.lastMenu;
delete MENU.skipUp;
}
var menu = HTML.addElement(div,"div",{
onmouseup: MENU.Mouseup, ondblclick: this.False,
ondragstart: this.False, onselectstart: this.False, oncontextmenu: this.False,
@ -189,15 +193,16 @@
if (!parent) {
if (x + menu.offsetWidth > document.body.offsetWidth - this.margin)
{x = document.body.offsetWidth - menu.offsetWidth - this.margin}
if (MENU.isMobile) {x -= menu.offsetWidth / 2; y -= 20}
MENU.skipUp = true;
} else {
var side = "left", mw = parent.offsetWidth;
x = parent.offsetWidth - 2; y = 0;
x = (MENU.isMobile ? 30 : mw - 2); y = 0;
while (parent && parent !== div) {
x += parent.offsetLeft; y += parent.offsetTop;
parent = parent.parentNode;
}
if (x + menu.offsetWidth > document.body.offsetWidth - this.margin)
if (x + menu.offsetWidth > document.body.offsetWidth - this.margin && !MENU.isMobile)
{side = "right"; x = Math.max(this.margin,x - mw - menu.offsetWidth + 6)}
if (!isPC) {
// in case these ever get implemented
@ -228,22 +233,46 @@
if (MENU.skipUp) {delete MENU.skipUp} else {this.Remove(event,menu)}
},
False: FALSE
False: FALSE,
/*
* Find a named item in a menu (or submenu).
* A lsit of names means descend into submenus.
*/
Find: function (name) {
var names = [].slice.call(arguments,1);
for (var i = 0, m = this.items.length; i < m; i++) {
if (this.items[i].name === name) {
if (names.length) {
if (!this.items[i].menu) {return null}
return this.items[i].menu.Find.apply(this.items[i].menu,names);
}
return this.items[i];
}
}
return null;
}
},{
config: CONFIG,
div: null, // the DOM elements for the menu and submenus
Remove: function (event) {MENU.Event(event,this,"Remove")},
Mouseover: function (event) {MENU.Event(event,this,"Mouseover")},
Mouseout: function (event) {MENU.Event(event,this,"Mouseout")},
Mousedown: function (event) {MENU.Event(event,this,"Mousedown")},
Mouseup: function (event) {MENU.Event(event,this,"Mouseup")},
Mousemove: function (event) {MENU.Event(event,this,"Mousemove")},
Remove: function (event) {return MENU.Event(event,this,"Remove")},
Mouseover: function (event) {return MENU.Event(event,this,"Mouseover")},
Mouseout: function (event) {return MENU.Event(event,this,"Mouseout")},
Mousedown: function (event) {return MENU.Event(event,this,"Mousedown")},
Mouseup: function (event) {return MENU.Event(event,this,"Mouseup")},
Touchstart: function (event) {return MENU.Event(event,this,"Touchstart")},
Touchend: function (event) {return MENU.Event(event,this,"Touchend")},
Event: function (event,menu,type) {
if (!event) {event = window.event}
var item = menu.menuItem;
//debug(type+" "+(item||{}).name);
//try {
if (item && item[type]) {return item[type](event,menu)}
//} catch (err) {debug(err.message)}
return null;
},
@ -300,8 +329,9 @@
if (!this.hidden) {
var def = {
onmouseover: MENU.Mouseover, onmouseout: MENU.Mouseout,
onmouseup: MENU.Mouseup, onmousedown: this.False,
onmouseup: MENU.Mouseup, onmousedown: MENU.Mousedown,
ondragstart: this.False, onselectstart: this.False, onselectend: this.False,
ontouchstart: MENU.Touchstart, ontouchend: MENU.Touchend,
className: "MathJax_MenuItem", menuItem: this
};
if (this.disabled) {def.className += " MathJax_MenuDisabled"}
@ -332,7 +362,20 @@
if (this.timer) {clearTimeout(this.timer); delete this.timer}
},
Mouseup: function (event,menu) {return this.Remove(event,menu)},
Touchstart: function (event,menu) {return this.TouchEvent(event,menu,"Mousedown")},
Touchend: function (event,menu) {return this.TouchEvent(event,menu,"Mouseup")},
TouchEvent: function (event,menu,type) {
if (this !== ITEM.lastItem) {
if (ITEM.lastMenu) {MENU.Event(event,ITEM.lastMenu,"Mouseout")}
MENU.Event(event,menu,"Mouseover");
ITEM.lastItem = this; ITEM.lastMenu = menu;
}
if (this.nativeTouch) {return null}
MENU.Event(event,menu,type);
return false;
},
Remove: function (event,menu) {
menu = menu.parentNode.menuItem;
return menu.Remove(event,menu);
@ -356,9 +399,10 @@
this.name = name; this.action = action;
this.With(def);
},
Label: function (def,menu) {return [this.name]},
Mouseup: function (event,menu) {
if (!this.disabled) {this.Remove(event,menu); this.action.call(this,event)}
if (!this.disabled) {this.Remove(event,menu); this.action.call(this,event);}
return this.False(event);
}
});
@ -377,7 +421,7 @@
this.menu = MENU.apply(MENU,[].slice.call(arguments,i));
},
Label: function (def,menu) {
def.onmousemove = MENU.Mousemove; this.menu.posted = false;
this.menu.posted = false;
return [this.name+" ",["span",{className:"MathJax_MenuArrow"},[this.marker]]];
},
Timer: function (event,menu) {
@ -385,6 +429,20 @@
event = {clientX: event.clientX, clientY: event.clientY}; // MSIE can't pass the event below
this.timer = setTimeout(MathJax.Callback(["Mouseup",this,event,menu]),CONFIG.delay);
},
Touchstart: function (event,menu) {
this.skipUp = !this.menu.posted;
return this.SUPER(arguments).Touchstart.apply(this,arguments);
},
Touchend: function (event,menu) {
var result = false;
if (!this.skipUp) {
var forceout = this.menu.posted;
result = this.SUPER(arguments).Touchend.apply(this,arguments);
if (forceout) {this.Deactivate(menu); delete ITEM.lastItem; delete ITEM.lastMenu}
}
delete this.skipUp;
return result;
},
Mouseup: function (event,menu) {
if (!this.disabled) {
if (!this.menu.posted) {
@ -599,19 +657,29 @@
var w = MENU.ShowSource.Window(event);
text = text.replace(/^\s*/,"").replace(/\s*$/,"");
text = text.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
w.document.open();
w.document.write("<html><head><title>MathJax Equation Source</title></head><body style='font-size:85%'>");
w.document.write("<table><tr><td><pre>"+text+"</pre></td></tr></table>");
w.document.write("</body></html>"); w.document.close();
var table = w.document.body.firstChild;
var H = (w.outerHeight-w.innerHeight)||30, W = (w.outerWidth-w.innerWidth)||30;
W = Math.min(Math.floor(.5*screen.width),table.offsetWidth+W+25);
H = Math.min(Math.floor(.5*screen.height),table.offsetHeight+H+25);
w.resizeTo(W,H);
if (event && event.screenX != null) {
var x = Math.max(0,Math.min(event.screenX-Math.floor(W/2), screen.width-W-20)),
y = Math.max(0,Math.min(event.screenY-Math.floor(H/2), screen.height-H-20));
w.moveTo(x,y);
if (MENU.isMobile) {
w.document.open();
w.document.write("<html><head><meta name='viewport' content='width=device-width, initial-scale=1.0' /><title>MathJax Equation Source</title></head><body style='font-size:85%'>");
w.document.write("<pre>"+text+"</pre>");
w.document.write("<hr><input type='button' value='Close' onclick='window.close()' />");
w.document.write("</body></html>");
w.document.close();
} else {
w.document.open();
w.document.write("<html><head><title>MathJax Equation Source</title></head><body style='font-size:85%'>");
w.document.write("<table><tr><td><pre>"+text+"</pre></td></tr></table>");
w.document.write("</body></html>");
w.document.close();
var table = w.document.body.firstChild;
var H = (w.outerHeight-w.innerHeight)||30, W = (w.outerWidth-w.innerWidth)||30;
W = Math.min(Math.floor(.5*screen.width),table.offsetWidth+W+25);
H = Math.min(Math.floor(.5*screen.height),table.offsetHeight+H+25);
w.resizeTo(W,H);
if (event && event.screenX != null) {
var x = Math.max(0,Math.min(event.screenX-Math.floor(W/2), screen.width-W-20)),
y = Math.max(0,Math.min(event.screenY-Math.floor(H/2), screen.height-H-20));
w.moveTo(x,y);
}
}
delete MENU.ShowSource.w;
};
@ -691,6 +759,8 @@
}
}
});
MENU.isMobile = MathJax.Hub.Browser.isMobile;
MENU.noContextMenu = MathJax.Hub.Browser.noContextMenu;
/*************************************************************/
@ -713,7 +783,7 @@
* The main menu
*/
MENU.menu = MENU(
ITEM.COMMAND("Show Source",MENU.ShowSource),
ITEM.COMMAND("Show Source",MENU.ShowSource,{nativeTouch: true}),
ITEM.SUBMENU("Format",
ITEM.RADIO("MathML", "format"),
ITEM.RADIO("Original", "format", {value: "Original"})
@ -772,16 +842,30 @@
MENU.showRenderer = function (show) {
MENU.cookie.showRenderer = CONFIG.showRenderer = show; MENU.saveCookie();
MENU.menu.items[3].menu.item[3].hidden = !show;
MENU.menu.Find("Settings","Math Renderer").hidden = !show;
};
MENU.showFontMenu = function (show) {
MENU.cookie.showFontMenu = CONFIG.showFontMenu = show; MENU.saveCookie();
MENU.menu.items[3].menu.items[4].hidden = !show
MENU.menu.Find("Settings","Font Preference").hidden = !show;
};
MENU.showContext = function (show) {
MENU.cookie.showContext = CONFIG.showContext = show; MENU.saveCookie();
MENU.menu.items[3].menu.items[5].hidden = !show
MENU.menu.Find("Settings","Contextual Menu").hidden = !show;
};
if (MENU.isMobile) {
(function () {
var settings = MathJax.Hub.config.menuSettings;
var trigger = MENU.menu.Find("Settings","Zoom Trigger").menu;
trigger.items[0].disabled = trigger.items[1].disabled = true;
if (settings.zoom === "Hover" || settings.zoom == "Click") {settings.zoom = "None"}
trigger.items = trigger.items.slice(0,4);
if (navigator.appVersion.match(/ Android /)) {
MathJax.Menu.ITEM.SUBMENU.Augment({marker: "\u00BB"});
}
})();
}
/*************************************************************/

View File

@ -24,7 +24,7 @@
MathJax.OutputJax["HTML-CSS"] = MathJax.OutputJax({
id: "HTML-CSS",
version: "1.1.5",
version: "1.1.6",
directory: MathJax.OutputJax.directory + "/HTML-CSS",
extensionDir: MathJax.OutputJax.extensionDir + "/HTML-CSS",
autoloadDir: MathJax.OutputJax.directory + "/HTML-CSS/autoload",

View File

@ -181,6 +181,57 @@
return def;
}
});
//
// 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 = {
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,this,event);
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();
HTMLCSS.DblClick.call(this,event.touches[0]||event.touch);
}
},
//
// If the timeout passes without an end event, we issue
// the contextual menu event.
//
menu: function (math,event) {
delete TOUCH.timeout; TOUCH.last = 0;
HTMLCSS.ContextMenu.call(math,event.touches[0]||even.touch);
}
};
HTMLCSS.Augment({
config: {
@ -261,6 +312,7 @@
LEFTBUTTON: (HUB.Browser.isMSIE ? 1 : 0), // the event.button value for left button
MENUKEY: "altKey", // the event value for alternate context menu
Touch: TOUCH, // Touch event handling
Font: null, // created by Config() below
Config: function () {
@ -385,6 +437,10 @@
className:"MathJax", oncontextmenu:this.ContextMenu, onmousedown: this.Mousedown,
onmouseover:this.Mouseover, onclick:this.Click, ondblclick:this.DblClick
});
if (MathJax.Hub.Browser.noContextMenu) {
span.ontouchstart = this.Touch.start;
span.ontouchend = this.Touch.end;
}
var blockMode = (math.Get("display") === "block");
if (blockMode) {
div = frame = this.Element("div",{className:"MathJax_Display", style:{width:"100%", position:"relative"}});
@ -434,7 +490,6 @@
[this,arguments.callee,EVENT,force] // call this function again
);
}
if (!event) {event = window.event}
if (event.preventDefault) {event.preventDefault()}
if (event.stopPropagation) {event.stopPropagation()}
event.cancelBubble = true;
@ -2210,7 +2265,6 @@
Safari: function (browser) {
var v3p0 = browser.versionAtLeast("3.0");
var v3p1 = browser.versionAtLeast("3.1");
browser.isMobile = (navigator.appVersion.match(/Mobile/i) != null);
var android = (navigator.appVersion.match(/ Android (\d+)\.(\d+)/));
var forceImages = (v3p1 && browser.isMobile && (
(navigator.platform.match(/iPad|iPod|iPhone/) && !browser.versionAtLeast("5.0")) ||

View File

@ -215,7 +215,6 @@
[this,arguments.callee,EVENT,force] // call this function again
);
}
if (!event) {event = window.event}
if (event.preventDefault) {event.preventDefault()}
if (event.stopPropagation) {event.stopPropagation()}
event.cancelBubble = true;