1

How can i use javascript jquery to find the div tag "main", and then from this div tag check if the first element that exists is a pre tag, and if it is a pre tag, then delete the leading white spaces?

<html>
<head>
    <script src="../js/load.js"></script>
</head>
<body>
<div id="docmap"></div>
<div id="main"><pre>
<!----------------------------------------------->
<!-- do not edit above
<!----------------------------------------------->

<h1>Jabberwocky 1</h1>
'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe:
All mimsy were the borogoves,
And the mome raths outgrabe.
</pre>
</div>
</body>
</html>

I'm thinking it needs to be something like this:

    var main   = $("#main");
    var pre  = main.find("pre");
    pre[0].htmlInner.textContent.replace(/^\s+/mg, "");
    //main.children("pre")[0].htmlInner.textContent.replace(/^\s+/mg, "")
pico
  • 1,660
  • 4
  • 22
  • 52
  • Are you aware that [let](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/let) and [const](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/const) are preferred over `var`? … and you can use the [main](https://developer.mozilla.org/docs/Web/HTML/Element/main) element instead of `
    ` — `main` is [supported by all browsers](https://caniuse.com/#feat=html5semantic)
    – Stephen P Feb 04 '20 at 18:41
  • 1
    Just FYI, that HTML is invalid. The second comment starts on the second line in the `pre` and ends at the end of the **third** line of the `pre` and contains the invalid sequence `` at the end of the second line.) – T.J. Crowder Feb 05 '20 at 07:48

2 Answers2

3

That approach won't work because of the HTML comment in the block. If the comments weren't there, your code wouldn't be far off, but:

  1. It's innerHTML, not htmlInner
  2. You have to assign the result of replace, it doesn't modify the string you call it on (more in this question's answers)

But that approach also has the problem that if you have any event handlers on anything in that pre element, they'll get removed by assigning to innerHTML.

But we need to handle the comment nodes, which means it's a tiny bit more complicated; see comments:

// Start with the first child of the `pre`
let node = document.querySelector("#main pre").firstChild;
// Stop when we run out of nodes or find the first element node
while (node && node.nodeType !== Node.ELEMENT_NODE) {
    const next = node.nextSibling;
    if (node.nodeType === Node.TEXT_NODE) {
        // Text node, remove leading whitespace
        node.nodeValue = node.nodeValue.trimStart();
        if (node.nodeValue) {
            // Non-empty text node after trimming; stop
            break;
        } else {
            // Empty text node, remove
            node.remove();
        }
    }
    node = next;
}

Live Example:

// Start with the first child of the `pre`
let node = document.querySelector("#main pre").firstChild;
// Stop when we run out of nodes or find the first element node
while (node && node.nodeType !== Node.ELEMENT_NODE) {
    const next = node.nextSibling;
    if (node.nodeType === Node.TEXT_NODE) {
        // Text node, remove leading whitespace
        node.nodeValue = node.nodeValue.trimStart();
        if (node.nodeValue) {
            // Non-empty text node after trimming; stop
            break;
        } else {
            // Empty text node, remove
            node.remove();
        }
    }
    node = next;
}
<div id="docmap"></div>
<div id="main"><pre>
<!----------------------------------------------->
<!-- do not edit above
<!----------------------------------------------->

<h1>Jabberwocky 1</h1>
'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe:
All mimsy were the borogoves,
And the mome raths outgrabe.
</pre>
</div>

That code assumes a modern browser, it won't work on IE11. If you need to support IE11, we have to remove any ES2015+ stuff (let, const, trimStart) and use removeChild rather than the newer remove:

// Start with the first child of the `pre`
var node = document.querySelector("#main pre").firstChild;
// Stop when we run out of nodes or find the first element node
while (node && node.nodeType !== Node.ELEMENT_NODE) {
    var next = node.nextSibling;
    if (node.nodeType === Node.TEXT_NODE) {
        // Text node, remove leading whitespace
        node.nodeValue = node.nodeValue.replace(/^\s+/g, ""); // No need for the `g` flag
        if (node.nodeValue) {
            // Non-empty text node after trimming; stop
            break;
        } else {
            // Empty text node, remove
            node.parentNode.removeChild(node);
        }
    }
    node = next;
}

Live Example:

// Start with the first child of the `pre`
var node = document.querySelector("#main pre").firstChild;
// Stop when we run out of nodes or find the first element node
while (node && node.nodeType !== Node.ELEMENT_NODE) {
    var next = node.nextSibling;
    if (node.nodeType === Node.TEXT_NODE) {
        // Text node, remove leading whitespace
        node.nodeValue = node.nodeValue.replace(/^\s+/g, ""); // No need for the `g` flag
        if (node.nodeValue) {
            // Non-empty text node after trimming; stop
            break;
        } else {
            // Empty text node, remove
            node.parentNode.removeChild(node);
        }
    }
    node = next;
}
<div id="docmap"></div>
<div id="main"><pre>
<!----------------------------------------------->
<!-- do not edit above
<!----------------------------------------------->

<h1>Jabberwocky 1</h1>
'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe:
All mimsy were the borogoves,
And the mome raths outgrabe.
</pre>
</div>

That works all the way back to IE9. (It would work in IE8 if you replaced Node.ELEMENT_NODE with 1 and Node.TEXT_NODE with 3.)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    I think the HTML comments within the `pre` still cause an issue. In a [separate question](https://stackoverflow.com/q/60062254/1921385) this OP is looking to remove all the white-space above the poem. Some of this white-space is caused by the comments which are not removed in this solution. Granted, this solution does meet the OP's requirements as stated so you get my upvote anyway. – Moob Feb 04 '20 at 18:46
  • @Moob - Thanks! I don't recall the HTML being in the question, so didn't see the comment nodes at the beginning of the `pre`. (Either it was a ninja edit in the first five minutes, or I was **really** not paying attention.) Fixed. Thanks again for the head's up! – T.J. Crowder Feb 05 '20 at 07:45
  • @StephenP - *"Does assigning to `innerText` rather than `innerHTML` also remove event handlers?"* Yes. – T.J. Crowder Feb 05 '20 at 07:50
2

Merely removing leading whitespace won't correct for the space at the top of your pre that is being created by the html comments. This simple function (not my own) will remove comments and whitespace-only text nodes.

var pre = document.querySelector("#main pre");

//The following is not my code! 
//Author: James Edwards
//See: https://www.sitepoint.com/removing-useless-nodes-from-the-dom/
function clean(node) {
  for (var n = 0; n < node.childNodes.length; n++) {
    var child = node.childNodes[n];
    if (
      child.nodeType === 8 ||
      (child.nodeType === 3 && !/\S/.test(child.nodeValue))
    ) {
      node.removeChild(child);
      n--;
    } else if (child.nodeType === 1) {
      clean(child);
    }
  }
}

clean(pre);
<div id="docmap"></div>
<div id="main">
  <pre>
<!----------------------------------------------->
<!-- do not edit above
<!----------------------------------------------->

<h1>Jabberwocky 1</h1>
'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe:
All mimsy were the borogoves,
And the mome raths outgrabe.
</pre>
</div>
Moob
  • 14,420
  • 1
  • 34
  • 47
  • 1
    Worth (?) noting that one can use the more readable `Node.COMMENT_NODE` etc constants to get rid of the magic numbers 8, 3, 1 – Stephen P Feb 04 '20 at 20:43