I’m trying to customize Anki cards using the following JavaScript code to prepend a <span>
containing the deck name to the first valid child element of the card’s .front
element. However, I’m running into issues when there are line breaks in the HTML of the card, like these examples:
Working examples:
<p>What are the echocardiographic parameters that indicate severe aortic stenosis?</p>
<div>What are the echocardiographic parameters that indicate severe aortic stenosis?</div><p>Text</p>
Not working examples:
<p>What are the echocardiographic
parameters that indicate severe aortic stenosis?</p>
<div>What are the echocardiographic parameters
that indicate severe aortic stenosis?</div>
<p>Text</p>
<div>What are the echocardiographic parameters that indicate severe aortic stenosis?</div>
<p>
Text
Text
Text
</p>
It seems the script fails to detect or process the <p>
or <div>
elements correctly if there are line breaks (even if they’re valid HTML). Here’s the relevant part of my code:
// Get the value of {{Deck}}.
var deckValue = "{{Deck}}";
// Split the string by the "::" character to get an array of elements.
var deckElements = deckValue.split("::");
// Get the last element of the string.
var lastElement = deckElements.pop();
// Remove the number followed by a period (and optional space), if it exists.
var cleanedElement = lastElement.replace(/^\d+\.\s*/, '');
// Add a period at the end of the deck name.
var finalElement = cleanedElement + ".";
var frenteElement = document.querySelector('.front'); // Select the main element
if (frenteElement) {
// Function to get the first valid child element, ignoring text nodes
function getFirstValidChild(element) {
return Array.from(element.childNodes).find(node => {
return node.nodeType === Node.ELEMENT_NODE; // Only HTML elements
});
}
// Function to clean text nodes inside an element
function cleanTextNodes(element) {
Array.from(element.childNodes).forEach(node => {
if (node.nodeType === Node.TEXT_NODE && !node.textContent.trim()) {
node.remove(); // Remove empty text nodes or those with only line breaks
}
});
}
// Clean text nodes in the root of {{Front}}
cleanTextNodes(frenteElement);
// Get the first valid child element
var firstChild = getFirstValidChild(frenteElement);
// Create the <span> with the deck content
var spanElement = document.createElement('span');
spanElement.id = "deck";
spanElement.textContent = finalElement + " "; // Add the content to the span
if (firstChild) {
// If the first element is <p>, add inside it
if (firstChild.tagName === 'P') {
console.log("First element is <p>. Adding inside.");
cleanTextNodes(firstChild); // Clean text nodes inside the <p>
firstChild.prepend(spanElement); // Add the <span> at the start of the <p>
} else {
console.log("First element is not <p>. Adding before the content.");
frenteElement.insertAdjacentElement('afterbegin', spanElement); // Add before the first element
}
} else {
// If no valid element is found, add it to the beginning of '.front'
console.log("No valid element found. Adding at the beginning of '.front'.");
frenteElement.insertAdjacentElement('afterbegin', spanElement);
}
} else {
console.error("Element '.front' not found."); // If {{Front}} is not found
}
It works perfectly if there are no line breaks, but as soon as the HTML has line breaks, the getFirstValidChild
function or the DOM manipulation seems to fail.
Questions:
- Why is the presence of line breaks affecting the script’s behavior, even though the HTML is valid?
- How can I make this code robust enough to handle line breaks in the card’s HTML?