-
Notifications
You must be signed in to change notification settings - Fork 3
/
templates.json
5 lines (5 loc) · 24.1 KB
/
templates.json
1
2
3
4
5
{
"front_template": "<script>\n // Loading Persistence\n // https://github.com/SimonLammer/anki-persistence\n // v0.5.2 - https://github.com/SimonLammer/anki-persistence/blob/62463a7f63e79ce12f7a622a8ca0beb4c1c5d556/script.js\n if (void 0 === window.Persistence) { var _persistenceKey = \"github.com/SimonLammer/anki-persistence/\", _defaultKey = \"_default\"; if (window.Persistence_sessionStorage = function () { var e = !1; try { \"object\" == typeof window.sessionStorage && (e = !0, this.clear = function () { for (var e = 0; e < sessionStorage.length; e++) { var t = sessionStorage.key(e); 0 == t.indexOf(_persistenceKey) && (sessionStorage.removeItem(t), e--) } }, this.setItem = function (e, t) { void 0 == t && (t = e, e = _defaultKey), sessionStorage.setItem(_persistenceKey + e, JSON.stringify(t)) }, this.getItem = function (e) { return void 0 == e && (e = _defaultKey), JSON.parse(sessionStorage.getItem(_persistenceKey + e)) }, this.removeItem = function (e) { void 0 == e && (e = _defaultKey), sessionStorage.removeItem(_persistenceKey + e) }) } catch (e) { } this.isAvailable = function () { return e } }, window.Persistence_windowKey = function (e) { var t = window[e], i = !1; \"object\" == typeof t && (i = !0, this.clear = function () { t[_persistenceKey] = {} }, this.setItem = function (e, i) { void 0 == i && (i = e, e = _defaultKey), t[_persistenceKey][e] = i }, this.getItem = function (e) { return void 0 == e && (e = _defaultKey), t[_persistenceKey][e] || null }, this.removeItem = function (e) { void 0 == e && (e = _defaultKey), delete t[_persistenceKey][e] }, void 0 == t[_persistenceKey] && this.clear()), this.isAvailable = function () { return i } }, window.Persistence = new Persistence_sessionStorage, Persistence.isAvailable() || (window.Persistence = new Persistence_windowKey(\"py\")), !Persistence.isAvailable()) { var titleStartIndex = window.location.toString().indexOf(\"title\"), titleContentIndex = window.location.toString().indexOf(\"main\", titleStartIndex); titleStartIndex > 0 && titleContentIndex > 0 && titleContentIndex - titleStartIndex < 10 && (window.Persistence = new Persistence_windowKey(\"qt\")) } }\n</script>\n\n{{#Image}}<p>{{Image}}</p>{{/Image}}\n\n<h3 id=\"myH1\"></h3>\n{{#Question}}<p>{{Question}}</p>{{/Question}}\n\n<div class=\"tappable\">\n <table style=\"border: 1px solid black\" id=\"qtable\"></table>\n</div>\n\n<div class=\"hidden\" id=\"Q_solutions\">{{Answers}}</div>\n<div class=\"hidden\" id=\"Card_Type\">{{QType (0=kprim,1=mc,2=sc)}}</div>\n\n<div class=\"hidden\" id=\"Q_1\">{{Q_1}}</div>\n<div class=\"hidden\" id=\"Q_2\">{{Q_2}}</div>\n<div class=\"hidden\" id=\"Q_3\">{{Q_3}}</div>\n<div class=\"hidden\" id=\"Q_4\"></div>\n<div class=\"hidden\" id=\"Q_5\"></div>\n\n<script>\n // Generate the table depending on the type.\n function generateTable() {\n var type = document.getElementById(\"Card_Type\").innerHTML;\n var table = document.createElement(\"table\");\n var tbody = document.createElement(\"tbody\");\n for (var i = 0; true; i++) {\n if (type == 0 && i == 0) {\n tbody.innerHTML = tbody.innerHTML + '<tr><th>yes</th><th>no</th><th></th></tr>';\n }\n if (document.getElementById('Q_' + (i + 1)) != undefined) {\n if (document.getElementById('Q_' + (i + 1)).innerHTML != '') {\n var html = [];\n\n let answerText = document.getElementById('Q_' + (i + 1)).innerHTML;\n let labelTag = (type == 0) ? '' :\n '<label for=\"inputQuestion' + (i + 1) + '\">' + answerText + '</label>';\n let textAlign = (type == 0) ? 'center' : 'left';\n\n html.push('<tr>');\n var maxColumns = ((type == 0) ? 2 : 1);\n for (var j = 0; j < maxColumns; j++) {\n let inputTag = '<input id=\"inputQuestion' + (i + 1) +\n '\" name=\"ans_' + ((type != 2) ? (i + 1) : 'A') +\n '\" type=\"' + ((type == 1) ? 'checkbox' : 'radio') +\n // TODO: I don't see how these values are used, please add a comment\n '\" value=\"' + ((j == 0) ? 1 : 0) + '\">';\n html.push(\n '<td onInput=\"onCheck()\" style=\"text-align: ' + textAlign + '\">' + inputTag +\n labelTag +\n '</td>');\n }\n if (type == 0) {\n html.push('<td>' + answerText + '</td>');\n }\n html.push('</tr>');\n tbody.innerHTML = tbody.innerHTML + html.join(\"\");\n }\n } else {\n break;\n }\n }\n\n table.appendChild(tbody);\n document.getElementById('qtable').innerHTML = table.innerHTML;\n onShuffle();\n }\n\n function shuffle(array) {\n var currentIndex = array.length, temporaryValue, randomIndex;\n\n // While there remain elements to shuffle...\n while (0 !== currentIndex) {\n\n // Pick a remaining element...\n randomIndex = Math.floor(Math.random() * currentIndex);\n currentIndex -= 1;\n\n // And swap it with the current element.\n temporaryValue = array[currentIndex];\n array[currentIndex] = array[randomIndex];\n array[randomIndex] = temporaryValue;\n }\n\n return array;\n }\n\n function onShuffle() {\n var solutions = document.getElementById(\"Q_solutions\").innerHTML;\n solutions = solutions.replace(/(<([^>]+)>)/gi, \"\").split(\" \");\n for (var i = 0; i < solutions.length; i++) {\n solutions[i] = Number(solutions[i]);\n }\n\n var output = document.getElementById(\"output\");\n\n var qrows = document.getElementById(\"qtable\").getElementsByTagName(\"tr\");\n\n var qanda = new Array();\n\n var type = document.getElementById(\"Card_Type\").innerHTML;\n\n for (i = 0; i < ((type == 0) ? qrows.length - 1 : qrows.length); i++) {\n qanda[i] = new Object();\n qanda[i].question = qrows[(type == 0) ? i + 1 : i].getElementsByTagName(\"td\")[(type == 0) ? 2 : 0].innerHTML;\n qanda[i].answer = solutions[i];\n }\n\n qanda = shuffle(qanda);\n\n var mc_solutions = new String();\n\n for (i = 0; i < ((type == 0) ? qrows.length - 1 : qrows.length); i++) {\n qrows[(type == 0) ? i + 1 : i].getElementsByTagName(\"td\")[(type == 0) ? 2 : 0].innerHTML = qanda[i].question;\n solutions[i] = qanda[i].answer;\n mc_solutions += qanda[i].answer + \" \";\n }\n mc_solutions = mc_solutions.substring(0, mc_solutions.lastIndexOf(\" \"));\n document.getElementById(\"Q_solutions\").innerHTML = mc_solutions;\n\n document.getElementById(\"qtable\").HTML = qrows;\n onCheck();\n }\n\n /**\n * Returns true if the option box/circle is checked.\n *\n * In case of kprim the second box is used as reference.\n *\n * @param {HTMLTableRowElement} optionRow Row containing option boxes/circles.\n * @param {number} index Index of the option in question.\n */\n function isOptionChecked(optionRow, index) {\n return optionRow.getElementsByTagName(\"td\")[index].getElementsByTagName(\"input\")[0].checked\n }\n\n function getUserAnswers() {\n let type = document.getElementById(\"Card_Type\").innerHTML;\n let qrows = document.getElementById(\"qtable\").getElementsByTagName('tbody')[0].getElementsByTagName(\"tr\");\n let userAnswers = [];\n for (let i = 0; i < qrows.length; i++) {\n if (type == 0 && i == 0) {\n i++; // to skip the first row containing no checkboxes when type is 'kprim'\n }\n if (type == 0) {\n if (isOptionChecked(qrows[i], 0)) {\n userAnswers.push(1);\n } else if (isOptionChecked(qrows[i], 1)) {\n userAnswers.push(0);\n } else {\n userAnswers.push(2);\n }\n } else {\n if (isOptionChecked(qrows[i], 0)) {\n userAnswers.push(1);\n } else {\n userAnswers.push(0);\n }\n }\n }\n return userAnswers\n }\n\n function getCorrectAnswers() {\n let solutions = document.getElementById(\"Q_solutions\").innerHTML.split(\" \").map(string => Number(string));\n\n return solutions;\n }\n\n /**\n * On checking an option this collects and stores answers in between front/back of the card.\n *\n * In case of kprim only the first box is looked at, if it isn't checked the second box has to be.\n * By default a '1' in the answers stands for 'yes' which is the first option from the left.\n */\n function onCheck() {\n // Send question table and encoded answers to Persistence along with the provided solutions\n if (Persistence.isAvailable()) {\n Persistence.clear();\n Persistence.setItem('user_answers', getUserAnswers());\n Persistence.setItem('Q_solutions', getCorrectAnswers());\n Persistence.setItem('qtable', document.getElementById(\"qtable\").innerHTML);\n }\n }\n\n function sleep(ms) {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n function tickCheckboxOnNumberKeyDown(event) {\n const keyName = event.key;\n\n let tableBody = document.getElementById(\"qtable\").getElementsByTagName('tbody')[0];\n var tableRows = tableBody.getElementsByTagName(\"tr\");\n\n if (0 < +keyName && +keyName < 10) {\n let tableData = tableRows[+keyName - 1].getElementsByTagName(\"td\")[0];\n let tableRow = tableData.getElementsByTagName(\"input\")[0];\n tableRow.checked = !tableRow.checked;\n onCheck();\n }\n }\n\n // addCheckboxTickingShortcuts is an easy approach on using only the keyboard to toggle checkboxes in mc/sc.\n //\n // Naturally the number keys are an intuitive choice here. Unfortunately anki does capture those.\n // So the workaround is to hold the (left) 'Alt' key and then type the corresponding number to toggle the row.\n function addCheckboxTickingShortcuts() {\n document.addEventListener('keydown', tickCheckboxOnNumberKeyDown, false);\n }\n\n function isMobile() {\n if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {\n return true;\n } else {\n return false;\n }\n }\n\n function run() {\n let DEFAULT_CARD_TYPE = 1; // for previewing the cards in \"Manage Note Type...\"\n\n if (isNaN(document.getElementById(\"Card_Type\").innerHTML)) {\n document.getElementById(\"Card_Type\").innerHTML = DEFAULT_CARD_TYPE;\n }\n\n if (document.getElementById(\"Card_Type\").innerHTML != 0 && !isMobile()) {\n addCheckboxTickingShortcuts();\n }\n\n setTimeout(generateTable(), 1);\n }\n\n async function waitForReadyStateAndRun() {\n for (let i = 0; i < 100; i++) {\n if (document.readyState === \"complete\") {\n run();\n break;\n }\n console.log(\"Document not yet fully loaded (readyState: \" + document.readyState + \"). Retry in 0.1s.\");\n await sleep(100);\n }\n }\n\n /*\n The following block is inspired by Glutanimate's Cloze Overlapper card template.\n The Cloze Overlapper card template is licensed under the CC BY-SA 4.0\n license (https://creativecommons.org/licenses/by-sa/4.0/).\n */\n if (document.readyState === \"complete\") {\n run();\n } else {\n waitForReadyStateAndRun();\n }\n</script>",
"back_template": "<script>\n // Loading Persistence\n // https://github.com/SimonLammer/anki-persistence\n // v0.5.2 - https://github.com/SimonLammer/anki-persistence/blob/62463a7f63e79ce12f7a622a8ca0beb4c1c5d556/script.js\n if (void 0 === window.Persistence) { var _persistenceKey = \"github.com/SimonLammer/anki-persistence/\", _defaultKey = \"_default\"; if (window.Persistence_sessionStorage = function () { var e = !1; try { \"object\" == typeof window.sessionStorage && (e = !0, this.clear = function () { for (var e = 0; e < sessionStorage.length; e++) { var t = sessionStorage.key(e); 0 == t.indexOf(_persistenceKey) && (sessionStorage.removeItem(t), e--) } }, this.setItem = function (e, t) { void 0 == t && (t = e, e = _defaultKey), sessionStorage.setItem(_persistenceKey + e, JSON.stringify(t)) }, this.getItem = function (e) { return void 0 == e && (e = _defaultKey), JSON.parse(sessionStorage.getItem(_persistenceKey + e)) }, this.removeItem = function (e) { void 0 == e && (e = _defaultKey), sessionStorage.removeItem(_persistenceKey + e) }) } catch (e) { } this.isAvailable = function () { return e } }, window.Persistence_windowKey = function (e) { var t = window[e], i = !1; \"object\" == typeof t && (i = !0, this.clear = function () { t[_persistenceKey] = {} }, this.setItem = function (e, i) { void 0 == i && (i = e, e = _defaultKey), t[_persistenceKey][e] = i }, this.getItem = function (e) { return void 0 == e && (e = _defaultKey), t[_persistenceKey][e] || null }, this.removeItem = function (e) { void 0 == e && (e = _defaultKey), delete t[_persistenceKey][e] }, void 0 == t[_persistenceKey] && this.clear()), this.isAvailable = function () { return i } }, window.Persistence = new Persistence_sessionStorage, Persistence.isAvailable() || (window.Persistence = new Persistence_windowKey(\"py\")), !Persistence.isAvailable()) { var titleStartIndex = window.location.toString().indexOf(\"title\"), titleContentIndex = window.location.toString().indexOf(\"main\", titleStartIndex); titleStartIndex > 0 && titleContentIndex > 0 && titleContentIndex - titleStartIndex < 10 && (window.Persistence = new Persistence_windowKey(\"qt\")) } }\n</script>\n\n<div style='font-family: \"Arial\"; font-size: 20px;'>{{#Image}}<p>{{Image}}</p>{{/Image}}</div>\n\n<h3 id=\"myH1\"></h3>\n{{#Question}}<p>{{Question}}</p>{{/Question}}\n<table id=\"qtable\"></table>\n<p id=\"output\"></p>\n<div class=\"hidden\" id=\"MC_solutions\">solutions_here</div>\n<div class=\"hidden\" id=\"user_answers\">user_answers_here</div>\n<div class=\"hidden\" id=\"CardType\">{{QType (0=kprim,1=mc,2=sc)}}</div>\n<p id=\"canswerresult\"><b>Correct answers: x %</b></p>\n{{#Sources}}<p class=\"small\" id=\"sources\"><b>Sources:</b><br />{{Sources}}</p>{{/Sources}}\n<p class=\"small\" id=\"extra1\"><b>Extra 1:</b><br /></p>\n\n<script>\n \"use strict\";\n\n function onLoad() {\n // Check if Persistence is recognized to prevent errors when viewing note in \"Manage Note Types...\"\n if (Persistence.isAvailable && Persistence.getItem('Q_solutions') !== null) {\n\n const DEFAULT_COLORING = { // Defines which class should be set\n wrongAndNotTicked: 'correct',\n correctAndTicked: 'correct',\n wrongButTicked: 'wrong',\n correctButNotTicked: 'wrong',\n withoutSelection: \"wrong\" // Kprim was marked neither correct nor wrong\n };\n\n const ALTERNATE_COLORING = { // Defines which class should be set\n wrongAndNotTicked: '',\n correctAndTicked: 'correct',\n wrongButTicked: 'wrong',\n correctButNotTicked: 'correct',\n withoutSelection: \"wrong\" // Kprim was marked neither correct nor wrong\n };\n\n // Options are modified according to user's meta.json in the addon's folder\n const OPTIONS = {\n qtable: {\n visible: true,\n colorize: true,\n colors: ALTERNATE_COLORING\n },\n atable: {\n visible: false,\n colorize: true,\n colors: ALTERNATE_COLORING\n }\n };\n\n const colorizeTableRow = function (row, tableType, solution, answer) {\n let colorOptions = OPTIONS[tableType].colors\n\n if ((solution === 1) && (answer === 1)) {\n row.setAttribute(\"class\", colorOptions.correctAndTicked);\n } else if ((solution === 0) && (answer === 0)) {\n row.setAttribute(\"class\", colorOptions.wrongAndNotTicked);\n } else if ((solution === 0) && (answer === 1)) {\n row.setAttribute(\"class\", colorOptions.wrongButTicked);\n } else if ((solution === 1) && (answer === 0)) {\n row.setAttribute(\"class\", colorOptions.correctButNotTicked);\n } else if (type == 0 && (answer === 2)) {\n row.setAttribute(\"class\", colorOptions.withoutSelection);\n }\n }\n\n // Parsing solutions\n var solutions = Persistence.getItem('Q_solutions');\n var answers = Persistence.getItem('user_answers');\n\n var type = document.getElementById('CardType').innerHTML;\n var qtable = document.getElementById('qtable');\n qtable.innerHTML = Persistence.getItem('qtable');\n\n // Clone atable from qtable before colorizing the qtable\n if (OPTIONS.atable.visible) {\n var output = document.getElementById(\"output\");\n var atable = qtable.cloneNode(true);\n atable.setAttribute(\"id\", \"atable\");\n output.innerHTML = \"<hr id='answer' />\" + atable.outerHTML;\n\n var arows = document.getElementById(\"atable\").getElementsByTagName(\"tbody\")[0].getElementsByTagName(\"tr\");\n }\n\n if (OPTIONS.qtable.visible) {\n var qrows = qtable.getElementsByTagName('tbody')[0].getElementsByTagName(\"tr\");\n for (let i = 0; i < answers.length; i++) {\n //Set the radio buttons in the qtable.\n if (type == 0) {\n if (answers[i] === 1) {\n let radioButton = qrows[i + 1].getElementsByTagName(\"td\")[0].getElementsByTagName(\"input\")[0];\n radioButton.checked = true;\n radioButton.disabled = true;\n } else if (answers[i] === 0) {\n let radioButton = qrows[i + 1].getElementsByTagName(\"td\")[1].getElementsByTagName(\"input\")[0];\n radioButton.checked = true;\n radioButton.disabled = true;\n }\n } else {\n let radioButton = qrows[i].getElementsByTagName(\"td\")[0].getElementsByTagName(\"input\")[0];\n radioButton.checked = (answers[i] === 1) ? true : false;\n radioButton.disabled = true;\n }\n //Colorize the qtable.\n if (OPTIONS.qtable.colorize) {\n colorizeTableRow(qrows[(type != 0) ? i : i + 1], \"qtable\", solutions[i], answers[i]);\n }\n }\n } else qtable.innerHTML = \"\"\n\n var canswers = 0;\n for (let i = 0; i < solutions.length; i++) {\n if (OPTIONS.atable.visible) {\n //Rename the radio buttons of the atable to avoid interference with those in the qtable.\n if (type == 0) arows[i + 1].getElementsByTagName(\"td\")[1].getElementsByTagName(\"input\")[0].setAttribute(\"name\", \"ans_\" + ((type != 2) ? String(i + 1) : 'A') + \"_solution\");\n arows[(type != 0) ? i : i + 1].getElementsByTagName(\"td\")[0].getElementsByTagName(\"input\")[0].setAttribute(\"name\", \"ans_\" + ((type != 2) ? String(i + 1) : 'A') + \"_solution\");\n //Set the radio buttons in the atable.\n if (type == 0) {\n let radioButton = arows[i + 1].getElementsByTagName(\"td\")[solutions[i] ? 0 : 1].getElementsByTagName(\"input\")[0];\n radioButton.checked = true;\n radioButton.disabled = true;\n }\n else {\n let radioButton = arows[i].getElementsByTagName(\"td\")[0].getElementsByTagName(\"input\")[0];\n radioButton.checked = solutions[i] ? true : false;\n radioButton.disabled = true;\n }\n //Colorize the atable.\n if (OPTIONS.atable.colorize) {\n colorizeTableRow(arows[(type != 0) ? i : i + 1], \"atable\", solutions[i], answers[i]);\n }\n }\n\n //Count correct answers.\n if (solutions[i] && answers[i] === 1) {\n canswers = canswers + 1;\n } else if (!solutions[i] && answers[i] === 0) {\n canswers = canswers + 1;\n }\n }\n }\n var canswerresult = document.getElementById(\"canswerresult\");\n if (type == 2) {\n canswerresult.innerHTML = \"<b>\" + ((canswers / solutions.length == 1) ? \"Correct.</b>\" : \"Nope.</b>\");\n } else {\n canswerresult.innerHTML = \"<b>Correct answers: \" + Math.round(canswers / solutions.length * 100) + \" %</b>\";\n }\n\n Persistence.clear();\n }\n\n function isMobile() {\n if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {\n return true;\n } else {\n return false;\n }\n }\n\n function sleep(ms) {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n function run() {\n if (!isMobile() && typeof tickCheckboxOnNumberKeyDown !== \"undefined\") {\n // To make sure there isn't a previously registered event handler lingering into the next review\n document.removeEventListener('keydown', tickCheckboxOnNumberKeyDown, false);\n }\n setTimeout(onLoad(), 1);\n }\n\n async function waitForReadyStateAndRun() {\n for (let i = 0; i < 100; i++) {\n if (document.readyState === \"complete\") {\n run();\n break;\n }\n console.log(\"Document not yet fully loaded (readyState: \" + document.readyState + \"). Retry in 0.1s.\");\n await sleep(100);\n }\n }\n\n /*\n The following block is inspired by Glutanimate's Cloze Overlapper card template.\n The Cloze Overlapper card template is licensed under the CC BY-SA 4.0\n license (https://creativecommons.org/licenses/by-sa/4.0/).\n */\n if (document.readyState === \"complete\") {\n run();\n } else if (isMobile()) {\n document.addEventListener(\"DOMContentLoaded\", function () {\n setTimeout(onLoad, 1);\n }, false);\n } else {\n waitForReadyStateAndRun();\n }\n</script>\n\n ",
"styling": ".card {\n font-family: arial;\n font-size: 20px;\n text-align: center;\n color: black;\n background-color: white;\n}\n\n.small {\n font-size: 15px;\n}\n\ntable, td, th {\n border-collapse: collapse;\n padding: 5px;\n}\n\ntable {\n display: inline-block;\n text-align: left;\n}\n\nlabel {\n margin-left: 0.4em;\n}\n\n.correct {\n background-color: lime;\n}\n\n.nightMode .correct {\n background-color: #009900;\n}\n\n.wrong {\n background-color: OrangeRed;\n}\n\n.hidden {\n /*\n This block is from Glutanimate's Cloze Overlapper card template.\n The Cloze Overlapper card template is licensed under the CC BY-SA 4.0\n license (https://creativecommons.org/licenses/by-sa/4.0/).\n */\n /* guarantees a consistent width across front and back */\n font-weight: bold;\n display: block;\n line-height: 0;\n height: 0;\n overflow: hidden;\n visibility: hidden;\n}\n img {\n display: block;\n margin: auto;\n width: 500px\n}"
}