Skip to content

Instantly share code, notes, and snippets.

@sartak
Forked from redoPop/anki_mobile_card.html
Last active February 18, 2023 17:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save sartak/581d3564dc42b689b604 to your computer and use it in GitHub Desktop.
Save sartak/581d3564dc42b689b604 to your computer and use it in GitHub Desktop.
HTML used by AnkiMobile 2.0.88 to render card templates; a reference for creating advanced Anki card templates with special HTML/CSS
<html>
<head>
<meta
name="viewport"
id="viewport"
content="width=device-width,initial-scale=1.0,maximum-scale=10,user-scalable=1"
/>
<link type="text/css" rel="stylesheet" href="res/web/css/reviewer.css" />
<script src="res/web/js/vendor/jquery.min.js"></script>
<script src="res/web/js/vendor/css_browser_selector.min.js"></script>
<script type="text/javascript" src="res/web/js/mathjax.js"></script>
<script
type="text/javascript"
src="res/web/js/vendor/mathjax/tex-chtml.js"
></script>
<script
src="/_anki/js/vendor/mathjax/input/tex/extensions/noerrors.js"
charset="UTF-8"
></script>
<script
src="/_anki/js/vendor/mathjax/input/tex/extensions/mathtools.js"
charset="UTF-8"
></script>
<script
src="/_anki/js/vendor/mathjax/input/tex/extensions/mhchem.js"
charset="UTF-8"
></script>
<style>
.missing-media {
background: white;
color: black;
border: 1px solid grey;
border-radius: 5px;
padding: 0.5em;
margin-top: 2em;
font-size: 14px;
display: none;
}
li {
text-align: left;
}
</style>
<style type="text/css">
.CtxtMenu_InfoClose {
top: 0.2em;
right: 0.2em;
}
.CtxtMenu_InfoContent {
overflow: auto;
text-align: left;
font-size: 80%;
padding: 0.4em 0.6em;
border: 1px inset;
margin: 1em 0px;
max-height: 20em;
max-width: 30em;
background-color: #eeeeee;
white-space: normal;
}
.CtxtMenu_Info.CtxtMenu_MousePost {
outline: none;
}
.CtxtMenu_Info {
position: fixed;
left: 50%;
width: auto;
text-align: center;
border: 3px outset;
padding: 1em 2em;
background-color: #dddddd;
color: black;
cursor: default;
font-family: message-box;
font-size: 120%;
font-style: normal;
text-indent: 0;
text-transform: none;
line-height: normal;
letter-spacing: normal;
word-spacing: normal;
word-wrap: normal;
white-space: nowrap;
float: none;
z-index: 201;
border-radius: 15px; /* Opera 10.5 and IE9 */
-webkit-border-radius: 15px; /* Safari and Chrome */
-moz-border-radius: 15px; /* Firefox */
-khtml-border-radius: 15px; /* Konqueror */
box-shadow: 0px 10px 20px #808080; /* Opera 10.5 and IE9 */
-webkit-box-shadow: 0px 10px 20px #808080; /* Safari 3 & Chrome */
-moz-box-shadow: 0px 10px 20px #808080; /* Forefox 3.5 */
-khtml-box-shadow: 0px 10px 20px #808080; /* Konqueror */
filter: progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color="gray", Positive="true"); /* IE */
}
</style>
<style type="text/css">
.CtxtMenu_MenuClose {
position: absolute;
cursor: pointer;
display: inline-block;
border: 2px solid #aaa;
border-radius: 18px;
-webkit-border-radius: 18px; /* Safari and Chrome */
-moz-border-radius: 18px; /* Firefox */
-khtml-border-radius: 18px; /* Konqueror */
font-family: "Courier New", Courier;
font-size: 24px;
color: #f0f0f0;
}
.CtxtMenu_MenuClose span {
display: block;
background-color: #aaa;
border: 1.5px solid;
border-radius: 18px;
-webkit-border-radius: 18px; /* Safari and Chrome */
-moz-border-radius: 18px; /* Firefox */
-khtml-border-radius: 18px; /* Konqueror */
line-height: 0;
padding: 8px 0 6px; /* may need to be browser-specific */
}
.CtxtMenu_MenuClose:hover {
color: white !important;
border: 2px solid #ccc !important;
}
.CtxtMenu_MenuClose:hover span {
background-color: #ccc !important;
}
.CtxtMenu_MenuClose:hover:focus {
outline: none;
}
</style>
<style type="text/css">
.CtxtMenu_Menu {
position: absolute;
background-color: white;
color: black;
width: auto;
padding: 5px 0px;
border: 1px solid #cccccc;
margin: 0;
cursor: default;
font: menu;
text-align: left;
text-indent: 0;
text-transform: none;
line-height: normal;
letter-spacing: normal;
word-spacing: normal;
word-wrap: normal;
white-space: nowrap;
float: none;
z-index: 201;
border-radius: 5px; /* Opera 10.5 and IE9 */
-webkit-border-radius: 5px; /* Safari and Chrome */
-moz-border-radius: 5px; /* Firefox */
-khtml-border-radius: 5px; /* Konqueror */
box-shadow: 0px 10px 20px #808080; /* Opera 10.5 and IE9 */
-webkit-box-shadow: 0px 10px 20px #808080; /* Safari 3 & Chrome */
-moz-box-shadow: 0px 10px 20px #808080; /* Forefox 3.5 */
-khtml-box-shadow: 0px 10px 20px #808080; /* Konqueror */
}
.CtxtMenu_MenuItem {
padding: 1px 2em;
background: transparent;
}
.CtxtMenu_MenuArrow {
position: absolute;
right: 0.5em;
padding-top: 0.25em;
color: #666666;
font-family: null;
font-size: 0.75em;
}
.CtxtMenu_MenuActive .CtxtMenu_MenuArrow {
color: white;
}
.CtxtMenu_MenuArrow.CtxtMenu_RTL {
left: 0.5em;
right: auto;
}
.CtxtMenu_MenuCheck {
position: absolute;
left: 0.7em;
font-family: null;
}
.CtxtMenu_MenuCheck.CtxtMenu_RTL {
right: 0.7em;
left: auto;
}
.CtxtMenu_MenuRadioCheck {
position: absolute;
left: 0.7em;
}
.CtxtMenu_MenuRadioCheck.CtxtMenu_RTL {
right: 0.7em;
left: auto;
}
.CtxtMenu_MenuInputBox {
padding-left: 1em;
right: 0.5em;
color: #666666;
font-family: null;
}
.CtxtMenu_MenuInputBox.CtxtMenu_RTL {
left: 0.1em;
}
.CtxtMenu_MenuComboBox {
left: 0.1em;
padding-bottom: 0.5em;
}
.CtxtMenu_MenuSlider {
left: 0.1em;
}
.CtxtMenu_SliderValue {
position: absolute;
right: 0.1em;
padding-top: 0.25em;
color: #333333;
font-size: 0.75em;
}
.CtxtMenu_SliderBar {
outline: none;
background: #d3d3d3;
}
.CtxtMenu_MenuLabel {
padding: 1px 2em 3px 1.33em;
font-style: italic;
}
.CtxtMenu_MenuRule {
border-top: 1px solid #dddddd;
margin: 4px 3px;
}
.CtxtMenu_MenuDisabled {
color: GrayText;
}
.CtxtMenu_MenuActive {
background-color: #606872;
color: white;
}
.CtxtMenu_MenuDisabled:focus {
background-color: #e8e8e8;
}
.CtxtMenu_MenuLabel:focus {
background-color: #e8e8e8;
}
.CtxtMenu_ContextMenu:focus {
outline: none;
}
.CtxtMenu_ContextMenu .CtxtMenu_MenuItem:focus {
outline: none;
}
.CtxtMenu_SelectionMenu {
position: relative;
float: left;
border-bottom: none;
-webkit-box-shadow: none;
-webkit-border-radius: 0px;
}
.CtxtMenu_SelectionItem {
padding-right: 1em;
}
.CtxtMenu_Selection {
right: 40%;
width: 50%;
}
.CtxtMenu_SelectionBox {
padding: 0em;
max-height: 20em;
max-width: none;
background-color: #ffffff;
}
.CtxtMenu_SelectionDivider {
clear: both;
border-top: 2px solid #000000;
}
.CtxtMenu_Menu .CtxtMenu_MenuClose {
top: -10px;
left: -10px;
}
</style>
</head>
<body class="card card1 nightMode night_mode">
<div id="qa" style="opacity: 0">
<style>
{{style}}
</style>
{{content}}
</div>
<div class="missing-media" style="display: none">
<div></div>
<div>
<a href="https://docs.ankimobile.net/syncing.html#missing-images"
>More Info</a
>
</div>
</div>
<script src="res/web/js/reviewer.js"></script>
<script src="res/web/js/reviewer_extras_bundle.js"></script>
</body>
</html>
"use strict";
var anki = (() => {
var p = Object.defineProperty;
var H = Object.getOwnPropertyDescriptor;
var k = Object.getOwnPropertyNames;
var z = Object.prototype.hasOwnProperty;
var _ = (e, t) => {
for (var n in t) p(e, n, { get: t[n], enumerable: !0 });
},
B = (e, t, n, o) => {
if ((t && typeof t == "object") || typeof t == "function")
for (let i of k(t))
!z.call(e, i) &&
i !== n &&
p(e, i, {
get: () => t[i],
enumerable: !(o = H(t, i)) || o.enumerable,
});
return e;
};
var q = (e) => B(p({}, "__esModule", { value: !0 }), e);
var s = (e, t, n) =>
new Promise((o, i) => {
var a = (r) => {
try {
l(n.next(r));
} catch (f) {
i(f);
}
},
c = (r) => {
try {
l(n.throw(r));
} catch (f) {
i(f);
}
},
l = (r) => (r.done ? o(r.value) : Promise.resolve(r.value).then(a, c));
l((n = n.apply(e, t)).next());
});
var de = {};
_(de, {
constrainViewport: () => V,
hideMissingImageWarning: () => se,
maybeShowMissingImageWarning: () => re,
pageDown: () => ce,
pageUp: () => ae,
playSound: () => ie,
rescaleText: () => M,
resetViewport: () => v,
runUserJs: () => le,
showAnswer: () => Q,
showQuestion: () => X,
});
var h = "preload-css",
y = document.createElement("template");
function w(e) {
return s(this, null, function* () {
F(), (y.innerHTML = e);
let t = D(y.content);
t.length &&
(yield Promise.race([
Promise.all(t.map(J)),
new Promise((n) => setTimeout(n, 500)),
]));
});
}
function F() {
[...document.head.getElementsByClassName(h)].forEach((e) => e.remove());
}
function D(e) {
return [...e.querySelectorAll("style, link")].filter(
(t) =>
(t instanceof HTMLStyleElement && t.innerHTML.includes("@import")) ||
(t instanceof HTMLLinkElement && t.rel === "stylesheet")
);
}
function J(e) {
return new Promise((t) => {
e.classList.add(h),
(e.media = "print"),
e.addEventListener("load", () => t()),
e.addEventListener("error", () => t()),
document.head.appendChild(e);
});
}
function U(e) {
return e.complete
? Promise.resolve()
: new Promise((t) => {
e.addEventListener("load", () => t()),
e.addEventListener("error", () => t());
});
}
function R(e) {
let t = document.createElement("template");
return (
(t.innerHTML = e),
[...t.content.querySelectorAll("img[src]")].map((i) => i.src)
);
}
function E(e) {
return s(this, null, function* () {
let t = R(e);
yield Promise.race([
Promise.all(
t.map((n) => {
let o = new Image();
return (o.src = n), U(o);
})
),
new Promise((n) => setTimeout(n, 100)),
]);
});
}
function V() {
document
.getElementById("viewport")
.setAttribute(
"content",
"width=device-width,initial-scale=1.0,maximum-scale=1"
);
}
function v() {
document
.getElementById("viewport")
.setAttribute(
"content",
"width=device-width,initial-scale=1.0,maximum-scale=10,user-scalable=1"
);
}
function Y() {
let e = document.getElementById("answer");
e == null || e.scrollIntoView({ behavior: "smooth" });
}
function j(e, t) {
for (let n of e.getElementsByTagName("video")) {
for (n.pause(); n.lastChild; ) n.removeChild(n.lastChild);
n.load();
}
e.innerHTML = t;
for (let n of e.querySelectorAll("script")) {
let o = document.createElement("script"),
i = n.attributes;
for (let a = 0; a < i.length; a++) {
let c = i[a];
o.setAttribute(c.name, c.value);
}
o.appendChild(document.createTextNode(n.innerHTML)),
n.parentNode.replaceChild(o, n);
}
}
var g = !1,
x = [],
S = [];
function T(e) {
let t = [];
for (let n = 0; n < e.length; n++) t.push(e[n]());
return Promise.all(t);
}
function L(e, t) {
return s(this, null, function* () {
for (; g; )
console.log("await qa update"),
yield new Promise((n) => setTimeout(() => n(), 50));
(m = !1), (x = [() => M(u), t]), (S = []);
try {
(g = !0), yield O(e);
} finally {
g = !1;
}
});
}
function O(e) {
return s(this, null, function* () {
yield w(e), yield E(e);
let t = document.getElementById("qa");
(t.style.opacity = "0"), v();
try {
j(t, e);
} catch (n) {
let o = e;
(o += "<div style='font-size: 14px;'>"),
(o += "This card contains a JS error: " + n),
(o +=
"<br><br>Please report the problem to the author of the deck.</div>"),
(t.innerHTML = o);
}
yield T(x),
yield MathJax.startup.promise.then(
() => (MathJax.typesetClear(), MathJax.typesetPromise([t]))
),
(t.style.opacity = "1"),
(t.style.display = "block"),
yield T(S);
});
}
var X = function (e, t, n) {
return s(this, null, function* () {
(document.body.className = t),
(u = n),
yield L(e, function () {
window.scrollTo({ top: 0, left: 0 });
});
});
},
Q = function (e, t) {
return s(this, null, function* () {
yield L(e, function () {
t && (document.body.className = t), Y();
});
});
};
function P(e) {
if (!!e) {
if (typeof e.childNodes != "undefined")
for (let t = 0; t < e.childNodes.length; t++) P(e.childNodes[t]);
if (typeof e.style != "undefined") {
let t = W(e);
if (!t) return;
e.style.fontSize = `${t / 10}rem`;
}
}
}
function W(e) {
let n = window.getComputedStyle(e).fontSize.match(/(\d+(.\d+)?)px/);
return n
? parseFloat(n[1])
: (console.log("couldn't get computed size"), 16);
}
var m = !1;
function G(e) {
if (e.toFixed(2) === "1.00" && !m) return;
m ||
((document.documentElement.style.fontSize = "62.5%"),
document.body.style.removeProperty("font-size"),
document.getElementById("qa").style.removeProperty("font-size"),
P(document.body),
(m = !0));
let n = 62.5 * e;
document.documentElement.style.fontSize = `${n}%`;
}
function K(e) {
(e = (e * 100).toFixed(0)),
(document.getElementsByTagName(
"body"
)[0].style.webkitTextSizeAdjust = `${e}%`);
}
var Z = navigator.userAgent.includes("iPad"),
u;
function M(e) {
e ? (u = e) : (e = u), Z ? G(e) : K(e);
}
var b = 0,
C = 0,
I = 0,
N = 0;
document.ontouchstart = function (e) {
(C = e.touches[0].clientX),
(I = e.touches[0].clientY),
(N = new Date().getTime());
};
function ee() {
let e = new Date().getTime();
return e - b > 100 ? ((b = e), !1) : !0;
}
document.ontouchend = function (e) {
if (ee()) {
e.preventDefault();
return;
}
te(e);
};
function te(e) {
if (ne(e) || new Date().getTime() - N > 300 || oe()) return;
let t = e.changedTouches[0].clientX,
n = e.changedTouches[0].clientY,
o = Math.abs(t - C),
i = Math.abs(n - I),
a = 30;
if (o > a || i > a) return;
let c = window.innerHeight / 3,
l = window.innerWidth / 3;
if (
((t = Math.floor(t / l)),
(n = Math.floor(n / c)),
t < 0 || t > 2 || n < 0 || n > 2)
)
return;
(t = ["Left", "Center", "Right"][t]), (n = ["top", "mid", "bottom"][n]);
let r = n + t;
d("ankitap", r), e.preventDefault();
}
function ne(e) {
let t = e.srcElement;
for (; t && t != document; ) {
if (
t.nodeName == "A" ||
t.onclick ||
t.nodeName == "BUTTON" ||
t.nodeName == "VIDEO" ||
t.nodeName == "SUMMARY" ||
t.nodeName == "INPUT" ||
t.getAttribute("contentEditable") ||
(t.classList && t.classList.contains("tappable"))
)
return !0;
t = t.parentNode;
}
return !1;
}
function oe() {
return !document.getSelection().isCollapsed;
}
globalThis.console = {
log: function (e) {
d("ankilog", e);
},
};
function d(e, t) {
let n = { scheme: e, msg: t };
try {
webkit.messageHandlers.cb.postMessage(JSON.stringify(n));
} catch (o) {
console.log(`error sending message: ${o}`);
}
}
function ie(e, t) {
d("playsound", { idx: e, questionSide: t });
}
function re(e) {
for (let t of document.getElementsByTagName("img")) {
let n = t.getAttribute("src");
if (n && decodeURIComponent(n) == e) {
let o = document.querySelector(".missing-media");
(o.children[0].textContent = `An image is missing: ${e}`),
(o.style.display = "block");
}
}
}
function se() {
let e = document.querySelector(".missing-media");
e.style.display = "none";
}
$(document).ready(function () {
d("ankiinternal", "DOMIsReady");
});
function ae() {
let e = window.scrollY + window.innerHeight * 0.9;
window.scrollBy({ top: -e, behavior: "smooth" });
}
function ce() {
let e = window.scrollY + window.innerHeight * 0.9;
window.scrollBy({ top: e, behavior: "smooth" });
}
function A(e) {
let t = document.activeElement,
n = !0;
t != null &&
(t.nodeName == "INPUT" ||
t.nodeName == "TEXTAREA" ||
(t.nodeName == "DIV" && t.getAttribute("contenteditable"))) &&
(n = !1),
d("allowShortcuts", JSON.stringify(n));
}
document.addEventListener("focus", A, !0);
document.addEventListener("blur", A, !0);
function le(e) {
try {
let t = globalThis[`userJs${e}`];
t ? t() : alert("Custom JS function not defined.");
} catch (t) {
alert(t);
}
}
return q(de);
})();
div {
overflow-wrap: break-word;
}
body {
text-align: center;
font-size: 1em;
-webkit-transform: translate3d(0, 0, 0);
-webkit-font-smoothing: antialiased;
font: -apple-system-body;
margin: 15px; /* Needs to be large enough that content doesn't underflow the bottom buttons when scrolling to the answer. */
margin-bottom: 100px;
margin-left: max(15px, env(safe-area-inset-left));
margin-right: max(15px, env(safe-area-inset-right));
}
img {
max-width: 95%;
}
.drawing {
zoom: 50%;
}
.nightMode img.drawing {
filter: invert() hue-rotate(180deg);
}
.nightMode .latex {
filter: invert() hue-rotate(180deg);
}
#typeans {
width: 95%;
margin-top: 5px;
}
.invis {
visibility: hidden;
}
.playImage {
-webkit-user-drag: none;
-webkit-user-select: none;
-webkit-touch-callout: none;
}
.soundLink {
-webkit-user-drag: none;
-webkit-user-select: none;
-webkit-touch-callout: none;
}
a.soundLink:active {
-webkit-tap-highlight-color: #00000000;
}
.soundLink {
text-decoration: none;
}
.replay-button svg {
width: 64px;
height: 64px;
}
.replay-button svg circle {
fill: #fff;
stroke: #414141;
}
.replay-button svg path {
fill: #414141;
}
.typeGood {
background: #afa;
color: black;
}
.typeBad {
color: black;
background: #faa;
}
.typeMissed {
color: black;
background: #ccc;
}
body.nightMode {
background-color: black;
color: white;
}
.nightMode a {
color: #77ccff;
}
// put this in a card template and sync to ankimobile
<script type="text/javascript">
function append(text) {
var source = document.createElement("div");
source.appendChild(document.createTextNode(text));
document.querySelector('body').appendChild(source);
}
if (true) {
append(document.querySelector('html').innerHTML);
}
if (true) {
fetch("res/web/css/reviewer.css").then((res) => {
return res.text()
}).then((res) => {
append(res);
})
}
if (true) {
fetch("res/web/js/reviewer.js").then((res) => {
return res.text()
}).then((res) => {
append(res);
})
}
if (true) {
fetch("res/web/js/reviewer_extras_bundle.js").then((res) => {
return res.text()
}).then((res) => {
append(res);
})
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment