I am aiming to replace each word in a document P tags with a span element. While the below code does the trick well for the first case, the following ones overlap, and start to destroy the HTML structure of our P tag completely. See image for unwanted output
Wondering if my approach is a wrong one, or would need some sorcery to only effect the innerHTML between the tags?
const runBionic = (node: ChildNode, paragraph: HTMLElement):HTMLElement => { if (node.textContent === null) return paragraph; const originalWords:string[] = node.textContent.split(" "); const filteredWords: string[] = originalWords.filter(word => word!=="" && word !== "n"); console.log("Filtered words: ", filteredWords); //replace each word with a span element filteredWords.forEach(word => { const modifiedWord = `<span style='font-weight: bold;'>${word}</span>`; console.log("REPLACING ", word, "WITH ", modifiedWord); paragraph.innerHTML = paragraph.innerHTML.replaceAll(word,modifiedWord); }); return paragraph;};
Aiming to eventually build a chrome extension that highlights the first 1/2 of the characters of any word on any page. This will help dyslexic people read the web faster. Attaching a link to the whole repo on github for context.
Advertisement
Answer
Okay, so I ended up with replacing the whole TextNode with a new span element instead. This way I can prepare the whole element and append it to its parent. Works perfectly, no regex needed….
const replaceNode = (node: ChildNode)=>{ if (node.textContent === null) return node; const newChild = document.createElement("span"); const words: string[] = node.textContent.split(" ").filter(word => word!=="" && word !== "n"); const HTMLstring: string = spannify(words); newChild.innerHTML = HTMLstring; return newChild;}; const spannify = (words : string[]) : string=>{ let HTMLstring = ""; words.forEach(word =>{ const span = `<span> ${word} </span>`; HTMLstring += span; }); return HTMLstring;};