Since there are a number of add-ons that makes it possible to run your own JavaScript in the editor through a shortcut or button press I thought it might be an idea to have somewhere to share useful JavaScript snippets. Some add-ons that allow for this are Custom editor keymap, Custom Styles and Wrapper meta-addon. I’ve never tried to last two but if I’ve understood things correctly it should be possible to use them for this purpose. There might be additional add-ons that can be used for this purpose as well.
My personal use case is for small repetitive actions that simply don’t merit developing a fully fledged add-on (i.e. ensuring edge-case functionality, proofing against user error documentation etc.). So feel free to share useful stuff you have, even if it is a quick hack without documentation or configurability.
I find myself creating a lot of tables with clozes in them, the following is a really rough parser for markdown tables (it really only parses | and newline) that creates an HTML table HTML from selection, i.e. retains images, HTML bold etc. It also inserts clozes in all cells except the first column using the next available cloze number. Do some logic changes to avoid inserting clozes on the first row PRN. Change styles PRN.
var sel = document.activeElement.shadowRoot.getSelection();
if (rng = sel.getRangeAt(0)) {
var ord = 1;
var html = document.activeElement.shadowRoot.activeElement.innerHTML;
var ahtml = [...html.matchAll(/{{c(\d+)::.*?}}/gs)];
if (ahtml.length >= 1) {
var max = ahtml.reduce(function(prev, curr) { return prev[1] > curr[1] ? prev : curr });
ord = parseInt(max[1]) + 1;
}
var outrows = [];
const table = '<table class="markdown-add" style="width: 100%; border-collapse: collapse;">';
const tr = '<tr class="markdown-add">';
const td = '<td class="markdown-add" style="border: 1px solid black; padding: 0px 5px 0px 5px;">';
var input = new XMLSerializer().serializeToString(rng.extractContents());
input = input.replace(/<br.*?>/gs, "<br>");
input = input.replace(/\sxmlns=".*?"/gs, "");
var inrows = input.split("<br>");
inrows.forEach(function (row) {
var outcells = [];
var incells = row.split("|");
outcells.push(incells.shift());
incells.forEach(cell => { outcells.push("{{c" + ord + "::" + cell.trim() + "}}"); });
outrows.push(tr + td + outcells.join('</td>' + td) + '</td></tr>');
});
rng.insertNode(rng.createContextualFragment(table + outrows.join("") + '</table>'));
sel.removeAllRanges();
sel.addRange(rng);
}
The following strips out div, span and p tags without attributes but keeping the content. Can be useful as some external editors per default use the “old” Anki behaviour of inserting div tags instead of br. Modify which tags to include and logic for flattening or not PRN.
var els = document.activeElement.shadowRoot.querySelectorAll("div, p, span");
els.forEach(el => {
if (!el.hasAttributes()) {
var parent = el.parentNode;
while (el.firstChild) parent.insertBefore(el.firstChild, el);
parent.removeChild(el);
}
});
I find myself creating a lot of tables with clozes in them, the following is a really rough parser for markdown tables (it really only parses | and newline) that creates an HTML table HTML from selection, i.e. retains images, HTML bold etc. It also inserts clozes in all cells except the first column using the next available cloze number. Change styles PRN.
New version:
Set HEADER to false prevent creating a header row from the first line
Set CLOZEFIRST to false before calling to prevent clozing the first column (in current config assumes {{cXX::!Something will lead to cloze being in shown state when inactive)
Set INCREASE to false to prevent incrementing clozes
Uppercase {var sel = document.activeElement.shadowRoot.getSelection(); for (i = 0; i < sel.rangeCount; i++) { var rng = sel.getRangeAt(i); var input = new XMLSerializer().serializeToString(rng.extractContents()); input = input.toUpperCase(); rng.insertNode(rng.createContextualFragment(input)); sel.addRange(rng);}}
Lowercase {var sel = document.activeElement.shadowRoot.getSelection(); for (i = 0; i < sel.rangeCount; i++) { var rng = sel.getRangeAt(i); var input = new XMLSerializer().serializeToString(rng.extractContents()); input = input.toLowerCase(); rng.insertNode(rng.createContextualFragment(input)); sel.addRange(rng);}}
“Sort” the clozes, i.e. rename them so that they are in ascending order in the note. Bear in mind that if you run this on a non-new note it will mess up your learning as it will not move the scheduling information. {
const html = document.activeElement.shadowRoot.activeElement.innerHTML;
const ahtml = […html.matchAll(new RegExp(/{{c(\d+)::.*?}}/gs))];
var ord = 1;
var ord_map = new Map();
for (el of ahtml) { if (!ord_map.has(parseInt(el[1]))) { ord_map.set(parseInt(el[1]), ord++); } };
document.activeElement.shadowRoot.activeElement.innerHTML = html.replace(/{{c(\d+)::/gs, function(match, p1) { return “{{c” + ord_map.get(parseInt(p1)) + “::”; });
}
function wrap(lhs, rhs) {
let root = document.activeElement.shadowRoot
let sel = root.getSelection()
let range = sel.getRangeAt(0)
let input = new XMLSerializer().serializeToString(range.extractContents())
newInput = lhs + input + rhs
range.insertNode(range.createContextualFragment(newInput))
sel.removeAllRanges()
sel.addRange(range)
rangeOffset = sel.getRangeAt(0).endOffset
sel.collapse(sel.focusNode, rangeOffset - rhs.length)
}
Function to wrap currently selected text or none with lhs and rhs, an example is more illustrative.
Thanks but I’m looking for something else.
I want the selected text size to change (not get the current size).
Thanks.
(I tried injecting a tag using the extension 1899278645 but it deletes any other formatting that is on the text. For example color)
Then the code I posted above should actually be of use to you. It allows you to get information about the currently selected node, as well as edit its attributes.
As I am not a coder I just want to share an idea. Since Remove Cloze Button and Hotkey hasn’t been updated since 2019-12-22 it would be awesome to have some java script to do it. Some regex can be used to achieve this: (\{\{c\d::|\}\}) - it works in Find and replace option - but would be great to have java script and keyboard shortcut or button to execute it when a piece of text is highlighted.