Why Doesn't My Script Work with Line Breaks in HTML on Anki Cards?

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:

  1. Why is the presence of line breaks affecting the script’s behavior, even though the HTML is valid?
  2. How can I make this code robust enough to handle line breaks in the card’s HTML?

Even in comments, {{field_name}} gets replaced with the field’s content. So, if {{Front}} contains multiple lines, lines like

    // Clean text nodes in the root of {{Front}}

or

    console.error("Element '.front' not found."); // If {{Front}} is not found

can break the script. Avoid using {{field_name}} in comments, and this should probably resolve the problem.

3 Likes

Oh, so simple!!!

Thank you!!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.