user961627
user961627

Reputation: 12747

Return text from tags where outermost HTML tags applies to all text nodes within - jquery

I have paragraphs of text that might be like this:

<p>
   <span style='font-family:arial'>
      Some text
   </span>
</p>

or

<p>
   <strong>
      Some more text
   <strong>
</p>

or

<p>
   <strong>
      <em>
         Yet more text
      </em>
   </strong>
</p>

However many nested tags there are, I'm able to get just the text, simply using $('p').text(). The problem is when <br> pops up in the middle. In that case, whatever tag the text is in gets broken up. So for example, this:

<p>
  <strong>
     Some more text
  </strong>
</p>

will turn into this:

<p>
  <strong>
     Some 
  </strong>
  <br />
  <strong>
     more text
  </strong>
</p>

So you see, there are now 2 text nodes in the <strong> tag, not just one. What I want to do is to get just the text with it's original parent tags, with <br> treated as just another text node, but without <br>-induced-tag-split-up intrusion. For example, given the 2-node HTML above, I just want a function that returns this:

<p>
  <strong>
     Some 
     <br />
     more text
  </strong>
</p>

That would be fine for a few given formats, but there could different types of HTML nesting that I need to retain (such as <p><strong><em> or <p><em><strong> or <p><strong><span> and so on.

Edit

Rather than getting lost in loops, I suppose the easiest way is to get the $('p').html() and simply chop away all tags around <br>? On the left there of <br> would be closing tags, on the right there would be opening tags. Would there be regex solution for this then?

Upvotes: 0

Views: 295

Answers (2)

Tomalak
Tomalak

Reputation: 338416

  1. find each <br> within a <p>
  2. for each of those <br> elements, compare the names of the immediately preceding and following elements
  3. if their names are equal, move the <br> and the contents of the following element into the preceding element
  4. remove the now empty following element

This:

$("p").clone().find("br").each(function() {
  var $this = $(this), $prev = $this.prev(), $next = $this.next();
  if ( $prev.length && $prev.prop("nodeName") === $next.prop("nodeName") ) {
    $prev.append( $this, $next.contents() );
    $next.remove();
  }
}).end().each(function () {
    console.log( $(this).html() );
});

(Note that I use clone() to avoid modifying the original.)

When applied to

<p>
  <strong>
     Some 
  </strong>
  <br />
  <strong>
     more text
  </strong>
</p>

writes this to the console

<strong>
   Some 
<br>
   more text
</strong>

http://jsfiddle.net/Tomalak/y3hSp/


Here is an iterative approach that collapses adjacent nodes that are separated by <br>, in form of a jQuery plugin:

$.fn.extend({
    collapseBreaks: function () {
        return this.each(function () {
            var done = false;

            while (!done) {
                done = true;

                $(this).find("br").each(function() {
                    var $this = $(this), 
                        $prev = $this.prev(), 
                        $next = $this.next();

                    if ( 
                        $prev.length 
                        && $prev.prop("nodeName") === $next.prop("nodeName") 
                    ) {
                        $prev.append( $this, $next.contents() );
                        $next.remove();
                        done = false;
                    }
                });       
            }
        });
    }
});

Use as

$("p").collapseBreaks(); 

http://jsfiddle.net/Tomalak/FJFgk/3/

Upvotes: 2

11684
11684

Reputation: 7517

So, what about:

var innerString = thatPFromYourQuestion.innerHTML;
innerString = innerString.replace("<.*>", "");

That should replace every tag with an empty string, returning all the text inside.

I think I misunderstood your question. If you just want literally what is in that paragraph, .innerHTML will do exactly that. If you want the <BR /> chopped of, you should use a slightly different version of that replace() call:

innerString = innerString.replace("<br>", "");

Upvotes: 1

Related Questions