Created
February 7, 2015 19:22
-
-
Save redoPop/10381ad5d576b9d73745 to your computer and use it in GitHub Desktop.
HTML used by AnkiMobile to render card templates; a reference for creating advanced Anki card templates with special HTML/CSS. When used by AnkiMobile, the card's HTML replaces the `<!-- (Card contents) -->` comment in this gist, with the shared styles dropped inline inside a `<style>` tag.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html class=" webkit safari mobile iphone js"> | |
<head> | |
<meta name="viewport" content="width=device-width;"> | |
<style id="ss"></style> | |
<style> | |
body { | |
text-align: center; | |
font-size: 1em; | |
-webkit-transform: translate3d(0,0,0); | |
-webkit-font-smoothing:antialiased; | |
} | |
img { | |
max-width: 95%; | |
} | |
#typeans { | |
width: 95%; | |
margin-top: 5px; | |
} | |
.invis { visibility:hidden; } | |
.card { margin: 20px; } | |
</style> | |
<script type="text/javascript"> | |
var typeans; | |
function setupType() { | |
typeans = document.getElementById("typeans"); | |
if (typeans) { | |
typeans.focus(); | |
} | |
$('.typeans').focus(); | |
} | |
function runScripts() { | |
var d = document.getElementById('qa').getElementsByTagName("script"); | |
var t = d.length; | |
for (var x = 0; x < t; x++) { | |
var newScript = document.createElement('script'); | |
newScript.type = "text/javascript"; | |
newScript.text = d[x].text; | |
document.getElementById('qa').appendChild(newScript); | |
} | |
} | |
// hack for ios7 to try make sure it refreshes the screen | |
function _refresh() { | |
setTimeout(function() { | |
var e = document.createElement('iframe'); | |
e.setAttribute('src', 'ankiinternal://foo'); | |
e.className = "invis"; | |
document.documentElement.appendChild(e); | |
e.parentNode.removeChild(e); | |
e = null; | |
//console.log('update');} | |
}, 0); | |
} | |
function _getTypedText() { | |
if (typeans) { | |
return typeans.value; | |
} | |
} | |
function _resizeImages(shrink) { | |
var elems = document.getElementsByTagName("img"); | |
for (var i=0; i<elems.length; i++) { | |
var e = elems[i]; | |
var w = e.style.maxWidth; | |
if (!w) { | |
// assume it's default 95% | |
w = "95%"; | |
} | |
w = parseInt(w, 10); | |
w += 30 * (shrink ? -1 : 1); | |
w = Math.max(30, w); | |
e.style.maxWidth = w+"%"; | |
} | |
} | |
// make console.log work | |
var console = { | |
log: function(msg) { | |
var iframe = document.createElement('IFRAME'); | |
iframe.setAttribute('src', 'ankilog://dummy/' + encodeURIComponent(msg)); | |
document.documentElement.appendChild(iframe); | |
iframe.parentNode.removeChild(iframe); | |
iframe = null; | |
} | |
}; | |
// tap handling | |
////////////////////////////////////////////////////////// | |
var _startX, _startY, _winX, _winY; | |
var _lastTap = 0; | |
var _tapStart; | |
var _tapReady = function(threshold) { | |
var now = new Date().getTime(); | |
var elapsed = now - _lastTap; | |
if (elapsed > threshold) { | |
_lastTap = now; | |
return true; | |
} | |
return false; | |
} | |
document.ontouchstart = function (e) { | |
_startX = e.touches[0].clientX; | |
_startY = e.touches[0].clientY; | |
_winX = _startX - window.pageXOffset; | |
_winY = _startY - window.pageYOffset; | |
_tapStart = new Date().getTime(); | |
}; | |
// this is run after the event bubbles up to the document | |
document.ontouchend = function (e) { | |
if (!_tapReady(300)) { | |
return; | |
} else if (_isLink(e)) { | |
return; | |
} else if ((new Date().getTime() - _tapStart) > 500) { | |
// long tap (eg copy), so ignore | |
return; | |
} | |
// if tap has moved, treat it as scrolling | |
var x = e.changedTouches[0].clientX; | |
var y = e.changedTouches[0].clientY; | |
var deltaX = Math.abs(x-_startX); | |
var deltaY = Math.abs(y-_startY); | |
var threshold = 30; | |
if (deltaX > threshold || deltaY > threshold) { | |
// if it was scrolling, we shouldn't use a touch delay | |
_lastTap = 0; | |
return; | |
} | |
// determine the section we're in | |
var tap; | |
var h = window.innerHeight / 3.0; | |
var w = window.innerWidth / 3.0; | |
x = Math.floor(x / w); | |
y = Math.floor(y / h); | |
if (x < 0 || x > 2 || y < 0 || y > 2) { | |
return; | |
} | |
x = ["Left", "Center", "Right"][x]; | |
y = ["top", "mid", "bottom"][y]; | |
tap = y+x; | |
// send tap to js | |
var iframe = document.createElement('IFRAME'); | |
iframe.setAttribute('src', 'ankitap://' + tap); | |
document.documentElement.appendChild(iframe); | |
iframe.parentNode.removeChild(iframe); | |
iframe = null; | |
}; | |
// this is run before any click events have a chance to fire | |
var _onclick = function (e) { | |
// if the target is not clickable, don't debounce | |
if (!_isLink(e)) { | |
return; | |
} | |
if (!_tapReady(1000)) { | |
e.stopPropagation(); | |
e.preventDefault(); | |
} | |
} | |
document.addEventListener("click", _onclick, true); | |
var _isLink = function(e) { | |
// we need to look at the source element and all parent elements | |
// except the document | |
var node = e.srcElement; | |
while (node && node != document) { | |
var res = (node.nodeName == "A" || node.onclick); | |
if (res) { | |
return true; | |
} | |
node = node.parentNode; | |
} | |
return res; | |
}; | |
// JS callback to indicate page fully loaded | |
var script = document.createElement('script'); | |
script.type = 'text/javascript'; | |
script.text = function DOMReady() { | |
var iframe = document.createElement('IFRAME'); | |
iframe.setAttribute('src', 'ankiinternal://DOMIsReady'); | |
document.documentElement.appendChild(iframe); | |
iframe.parentNode.removeChild(iframe); | |
iframe = null; | |
}; | |
function addScript() { | |
document.getElementsByTagName('head')[0].appendChild(script); | |
document.addEventListener('DOMContentLoaded', DOMReady, false); | |
} | |
addScript(); | |
/* browsersel.js 0.4.0 */ | |
function css_browser_selector(u) { | |
var ua = u.toLowerCase(), | |
is = function(t) { | |
return ua.indexOf(t) > -1 | |
}, | |
g = 'gecko', | |
w = 'webkit', | |
s = 'safari', | |
o = 'opera', | |
m = 'mobile', | |
h = document.documentElement, | |
b = [(!(/opera|webtv/i.test(ua)) && /msie\s(\d)/.test(ua)) ? ('ie ie' + RegExp.$1) : is('firefox/2') ? g + ' ff2' : is('firefox/3.5') ? g + ' ff3 ff3_5' : is('firefox/3.6') ? g + ' ff3 ff3_6' : is('firefox/3') ? g + ' ff3' : is('gecko/') ? g : is('opera') ? o + (/version\/(\d+)/.test(ua) ? ' ' + o + RegExp.$1 : (/opera(\s|\/)(\d+)/.test(ua) ? ' ' + o + RegExp.$2 : '')) : is('konqueror') ? 'konqueror' : is('blackberry') ? m + ' blackberry' : is('android') ? m + ' android' : is('chrome') ? w + ' chrome' : is('iron') ? w + ' iron' : is('applewebkit/') ? w + ' ' + s + (/version\/(\d+)/.test(ua) ? ' ' + s + RegExp.$1 : '') : is('mozilla/') ? g : '', is('j2me') ? m + ' j2me' : is('iphone') ? m + ' iphone' : is('ipod') ? m + ' ipod' : is('ipad') ? m + ' ipad' : is('mac') ? 'mac' : is('darwin') ? 'mac' : is('webtv') ? 'webtv' : is('win') ? 'win' + (is('windows nt 6.0') ? ' vista' : '') : is('freebsd') ? 'freebsd' : (is('x11') || is('linux')) ? 'linux' : '', 'js']; | |
c = b.join(' '); | |
h.className += ' ' + c; | |
return c; | |
}; | |
css_browser_selector(navigator.userAgent); | |
/* fastclick 0.5.0 */ | |
function FastClick(e) { | |
"use strict"; | |
var t, n = this; | |
this.trackingClick = false; | |
this.trackingClickStart = 0; | |
this.targetElement = null; | |
this.touchStartX = 0; | |
this.touchStartY = 0; | |
this.lastTouchIdentifier = 0; | |
this.layer = e; | |
if (!e || !e.nodeType) { | |
throw new TypeError("Layer must be a document node") | |
} | |
this.onClick = function() { | |
FastClick.prototype.onClick.apply(n, arguments) | |
}; | |
this.onTouchStart = function() { | |
FastClick.prototype.onTouchStart.apply(n, arguments) | |
}; | |
this.onTouchMove = function() { | |
FastClick.prototype.onTouchMove.apply(n, arguments) | |
}; | |
this.onTouchEnd = function() { | |
FastClick.prototype.onTouchEnd.apply(n, arguments) | |
}; | |
this.onTouchCancel = function() { | |
FastClick.prototype.onTouchCancel.apply(n, arguments) | |
}; | |
if (typeof window.ontouchstart === "undefined") { | |
return | |
} | |
e.addEventListener("click", this.onClick, true); | |
e.addEventListener("touchstart", this.onTouchStart, false); | |
e.addEventListener("touchmove", this.onTouchMove, false); | |
e.addEventListener("touchend", this.onTouchEnd, false); | |
e.addEventListener("touchcancel", this.onTouchCancel, false); | |
if (!Event.prototype.stopImmediatePropagation) { | |
e.removeEventListener = function(t, n, r) { | |
var i = Node.prototype.removeEventListener; | |
if (t === "click") { | |
i.call(e, t, n.hijacked || n, r) | |
} else { | |
i.call(e, t, n, r) | |
} | |
}; | |
e.addEventListener = function(t, n, r) { | |
var i = Node.prototype.addEventListener; | |
if (t === "click") { | |
i.call(e, t, n.hijacked || (n.hijacked = function(e) { | |
if (!e.propagationStopped) { | |
n(e) | |
} | |
}), r) | |
} else { | |
i.call(e, t, n, r) | |
} | |
} | |
} | |
if (typeof e.onclick === "function") { | |
t = e.onclick; | |
e.addEventListener("click", function(e) { | |
t(e) | |
}, false); | |
e.onclick = null | |
} | |
} | |
FastClick.prototype.deviceIsAndroid = navigator.userAgent.indexOf("Android") > 0; | |
FastClick.prototype.deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent); | |
FastClick.prototype.deviceIsIOS4 = FastClick.prototype.deviceIsIOS && /OS 4_\d(_\d)?/.test(navigator.userAgent); | |
FastClick.prototype.needsClick = function(e) { | |
"use strict"; | |
switch (e.nodeName.toLowerCase()) { | |
case "label": | |
case "video": | |
return true; | |
default: | |
return /\bneedsclick\b/.test(e.className) | |
} | |
}; | |
FastClick.prototype.needsFocus = function(e) { | |
"use strict"; | |
switch (e.nodeName.toLowerCase()) { | |
case "textarea": | |
case "select": | |
return true; | |
case "input": | |
switch (e.type) { | |
case "button": | |
case "checkbox": | |
case "file": | |
case "image": | |
case "radio": | |
case "submit": | |
return false | |
} | |
return true; | |
default: | |
return /\bneedsfocus\b/.test(e.className) | |
} | |
}; | |
FastClick.prototype.sendClick = function(e, t) { | |
"use strict"; | |
var n, r; | |
if (document.activeElement && document.activeElement !== e) { | |
document.activeElement.blur() | |
} | |
r = t.changedTouches[0]; | |
n = document.createEvent("MouseEvents"); | |
n.initMouseEvent("click", true, true, window, 1, r.screenX, r.screenY, r.clientX, r.clientY, false, false, false, false, 0, null); | |
n.forwardedTouchEvent = true; | |
e.dispatchEvent(n) | |
}; | |
FastClick.prototype.focus = function(e) { | |
"use strict"; | |
var t; | |
if (this.deviceIsIOS && e.setSelectionRange) { | |
t = e.value.length; | |
e.setSelectionRange(t, t) | |
} else { | |
e.focus() | |
} | |
}; | |
FastClick.prototype.updateScrollParent = function(e) { | |
"use strict"; | |
var t, n; | |
t = e.fastClickScrollParent; | |
if (!t || !t.contains(e)) { | |
n = e; | |
do { | |
if (n.scrollHeight > n.offsetHeight) { | |
t = n; | |
e.fastClickScrollParent = n; | |
break | |
} | |
n = n.parentElement | |
} while (n) | |
} | |
if (t) { | |
t.fastClickLastScrollTop = t.scrollTop | |
} | |
}; | |
FastClick.prototype.onTouchStart = function(e) { | |
"use strict"; | |
var t, n; | |
t = e.target; | |
n = e.targetTouches[0]; | |
if (this.deviceIsIOS) { | |
if (window.getSelection().rangeCount) { | |
return true | |
} | |
if (!this.deviceIsIOS4) { | |
if (n.identifier === this.lastTouchIdentifier) { | |
e.preventDefault(); | |
return false | |
} | |
this.lastTouchIdentifier = n.identifier; | |
this.updateScrollParent(t) | |
} | |
} | |
this.trackingClick = true; | |
this.trackingClickStart = e.timeStamp; | |
this.targetElement = t; | |
this.touchStartX = n.pageX; | |
this.touchStartY = n.pageY; | |
if (e.timeStamp - this.lastClickTime < 200) { | |
e.preventDefault() | |
} | |
return true | |
}; | |
FastClick.prototype.touchHasMoved = function(e) { | |
"use strict"; | |
var t = e.targetTouches[0]; | |
if (Math.abs(t.pageX - this.touchStartX) > 10 || Math.abs(t.pageY - this.touchStartY) > 10) { | |
return true | |
} | |
return false | |
}; | |
FastClick.prototype.onTouchMove = function(e) { | |
"use strict"; | |
if (!this.trackingClick) { | |
return true | |
} | |
if (this.targetElement !== e.target || this.touchHasMoved(e)) { | |
this.trackingClick = false; | |
this.targetElement = null | |
} | |
return true | |
}; | |
FastClick.prototype.findControl = function(e) { | |
"use strict"; | |
if (e.control !== undefined) { | |
return e.control | |
} | |
if (e.htmlFor) { | |
return document.getElementById(e.htmlFor) | |
} | |
return e.querySelector("button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea") | |
}; | |
FastClick.prototype.onTouchEnd = function(e) { | |
"use strict"; | |
var t, n, r, i, s = this.targetElement; | |
if (!this.trackingClick) { | |
return true | |
} | |
if (e.timeStamp - this.lastClickTime < 200) { | |
this.cancelNextClick = true; | |
return true | |
} | |
this.lastClickTime = e.timeStamp; | |
n = this.trackingClickStart; | |
this.trackingClick = false; | |
this.trackingClickStart = 0; | |
r = s.tagName.toLowerCase(); | |
if (r === "label") { | |
t = this.findControl(s); | |
if (t) { | |
this.focus(s); | |
if (this.deviceIsAndroid) { | |
return false | |
} | |
s = t | |
} | |
} else if (this.needsFocus(s)) { | |
if (e.timeStamp - n > 100 || this.deviceIsIOS && window.top !== window && r === "input") { | |
this.targetElement = null; | |
return false | |
} | |
this.focus(s); | |
if (!this.deviceIsIOS4 || r !== "select") { | |
this.targetElement = null; | |
e.preventDefault() | |
} | |
return false | |
} | |
if (this.deviceIsIOS && !this.deviceIsIOS4) { | |
i = s.fastClickScrollParent; | |
if (i && i.fastClickLastScrollTop !== i.scrollTop) { | |
return true | |
} | |
} | |
if (!this.needsClick(s)) { | |
e.preventDefault(); | |
this.sendClick(s, e) | |
} | |
return false | |
}; | |
FastClick.prototype.onTouchCancel = function() { | |
"use strict"; | |
this.trackingClick = false; | |
this.targetElement = null | |
}; | |
FastClick.prototype.onClick = function(e) { | |
"use strict"; | |
var t; | |
if (!this.targetElement) { | |
return true | |
} | |
if (e.forwardedTouchEvent) { | |
return true | |
} | |
t = this.targetElement; | |
this.targetElement = null; | |
if (this.trackingClick) { | |
this.trackingClick = false; | |
return true | |
} | |
if (!e.cancelable) { | |
return true | |
} | |
if (e.target.type === "submit" && e.detail === 0) { | |
return true | |
} | |
if (!this.needsClick(t) || this.cancelNextClick) { | |
this.cancelNextClick = false; | |
if (e.stopImmediatePropagation) { | |
e.stopImmediatePropagation() | |
} else { | |
e.propagationStopped = true | |
} | |
e.stopPropagation(); | |
e.preventDefault(); | |
return false | |
} | |
return true | |
}; | |
FastClick.prototype.destroy = function() { | |
"use strict"; | |
var e = this.layer; | |
e.removeEventListener("click", this.onClick, true); | |
e.removeEventListener("touchstart", this.onTouchStart, false); | |
e.removeEventListener("touchmove", this.onTouchMove, false); | |
e.removeEventListener("touchend", this.onTouchEnd, false); | |
e.removeEventListener("touchcancel", this.onTouchCancel, false) | |
}; | |
if (typeof define !== "undefined" && define.amd) { | |
define(function() { | |
"use strict"; | |
return FastClick | |
}) | |
} | |
if (typeof module !== "undefined" && module.exports) { | |
module.exports = function(e) { | |
"use strict"; | |
return new FastClick(e) | |
}; | |
module.exports.FastClick = FastClick | |
} | |
window.addEventListener('load', function() { | |
new FastClick(document.body); | |
}, false); | |
</script> | |
<script type="text/javascript"> | |
function DOMReady() { | |
var iframe = document.createElement('IFRAME'); | |
iframe.setAttribute('src', 'ankiinternal://DOMIsReady'); | |
document.documentElement.appendChild(iframe); | |
iframe.parentNode.removeChild(iframe); | |
iframe = null; | |
} | |
</script> | |
<title></title> | |
</head> | |
<body class="card card1"> | |
<div id="qa"> | |
<!-- | |
(Card contents) | |
--> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Extracted from AnkiMobile for iOS, version 2.0.17 (the Jan 4, 2015 update).