4

I'm trying to edit some HTML using JSDOM within Node.JS. I want any <blockquote> that is the child of at most one surrounding <div> to be removed. But I want any <blockquote> tag that is inside two or more <div>s to remain. I have read this question but I am still confused. You can see what I have tried in this JSFiddle. Here is the original HTML:

<html>
    <div id="div1">
        <blockquote>Text 1</blockquote>
    </div>
    <div id="div2"> 
        <div id="div3"> 
            <blockquote>Text 2</blockquote>
            <div id="div4">
                <blockquote>Text 3</blockquote>
            </div>
        </div>
    </div>
<span onclick="removeblockquotes(this)">Change</span>
</html>

Should turn into

<html>
    <div id="div1">
        Text 1
    </div>
    <div id="div2"> 
        <div id="div3"> 
            <blockquote>Text 2</blockquote>
            <div id="div4">
                <blockquote>Text 3</blockquote>
            </div>
        </div>
    </div>
</html>

Here is the function I have tried so far, but it isn't working (none of the blockquotes are changing):

function removeblockquotes(e)
{
var x = document.querySelectorAll("blockquote"); 
x.forEach(y=>{
    if (y.parentNode.parentNode==null){
        y.parentNode.appendChild(x.innerHTML);
        y.parentNode.removeChild(x);
    };
});
}
garson
  • 1,505
  • 3
  • 22
  • 56

1 Answers1

0

Just chain two .closest calls onto each blockquote to see if there's more than one surrounding div:

for (const b of document.querySelectorAll('blockquote')) {
  if (!b.closest('div')?.parentElement.closest('div')) {
    b.replaceWith(b.textContent);
  }
}
console.log(document.body.innerHTML);
<div id="div1">
    <blockquote>Text 1</blockquote>
</div>
<div id="div2"> 
    <div id="div3"> 
        <blockquote>Text 2</blockquote>
        <div id="div4">
            <blockquote>Text 3</blockquote>
        </div>
    </div>
</div>

(you need a single .parentElement because .closest will return the element it's called on if it matches)

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Amazing. Had never heard of .closest before. Sometimes I think there's a big glossary of cool JS functions I've somehow never seen. – garson Mar 09 '21 at 05:24
  • Hmm. This works in the JSFiddle but when I try implementing in my node.js file I get "SyntaxError: Unexpected token '.'" – garson Mar 09 '21 at 05:38
  • You must be using an old Node version that doesn't support optional chaining. Best solution would be to upgrade your Node. If you can't do that, store the first div in a variable and check if it's not null before proceeding to the `parentElement` – CertainPerformance Mar 09 '21 at 05:39
  • You need optional chaining (or the equivalent) so as not to throw an error if *no* `
    ` parent exists.
    – CertainPerformance Mar 09 '21 at 05:39
  • Just changed the version in package.js from 12.x to 14.x. Now it works, thanks. I'm having some issues when the inside of the
    contains HTML tags but I can work those out separately.
    – garson Mar 09 '21 at 05:47