How not to slice the links displayed in <p> element using jquery?

Hello all!

I have a jquery code used to show more or less link for the comments displayed from my database. I noticed that this jquery code can’t display the link properly that is queried from the database and some can display well. Some instances that the link won’t display properly are as follows:

1.If you are entering long comments with several paragraphs and there’s link in it

  1. Mostly, if the link is located at the middle of the first paragraph, the link is not displayed properly.

  2. If you enter long string link

  3. Lastly, if you enter all several links in a vertical order, the last link won’t display as link when the ‘show more’ link is clicked.

I suspect that it has something to do with my jquery code because it can only display the link properly when the link is located at the first line of the paragraph and anywhere in the second paragraph. I noticed on that jquery code below that if the link is located within the range of 0- 126 characters it will be displayed fine as a link, but if the link will go beyond 126th character where it cuts, then the link from the database is now ruined and not displaying as a link where it should supposed to be. I could hardly figure out how to do this on jquery…Any idea? Anybody can give me a jquery code that would handle in displaying links on the page where ever the links is located in any paragraph? Or help me modify my codes perhaps…Here’s my jquery code for ‘More Less’ link. Thanks for any help…

$(function() {
	var minimized_elements = $('p.minimize');
	minimized_elements.each(function() {
		var t = $(this).text();
		if (t.length < 126) return;
		$(this).html(t.slice(0, 126) + '<span>... </span><a href="#" class="more">More</a>' + '<span style="display:none;">' + t.slice(126, t.length) + ' <a href="#" class="less">Less</a></span>');
	});
	$('a.more', minimized_elements).click(function(event) {
		event.preventDefault();
		$(this).hide().prev().hide();
		$(this).next().show();
	});
	$('a.less', minimized_elements).click(function(event) {
		event.preventDefault();
		$(this).parent().hide().prev().show().prev().show();
	});
});

Hi timmack, welcome to the forums.

The problem you’re having is because “slice 126” chops the string without taking tag pairs into account.

Not only could this break links, but is likely to cause invalid mark-up as well. eg. “…</sp”, “<div>…”
The only way I can think to do it is to parse the string for tag pairs before slicing it and then either shorten or lengthen the slice point. i.e. instead of “126” use a variable determined from the parse results.

Does jquery have such a function?

That is the big question I’m facing now because I don’t know how to modify my jquery codes to parse the string from tag pairs before slicing it. Can you give me an idea on how do I use a variable determined from the parse result cause I’m new to jquery and not yet too fluent with this language…Thanks I hope you can help me.

Writing your own parser could be gnarly, hopefully someone knows about something I don’t know about. I’ll look through my jquery book for ideas in the meantime and try to post back after I get some sleep.

it could be something like

slice(0, length_of_string_that_has_well-formed_markup)

slice(0, length_of_string_that_has_well-formed_markup) from this line: length_of_string_that_has_well-formed_markup? is how to determine that in jquery? Also I guess I need to identify the <a>Links within the paragraph</a> from bypassing in slicing then so they won’t be broken in the paragraph. Still not sure how to do this…

That was only to show where to put the variable to control the slice()
How to get its value is the problem.

I looked a bit for an existing solution but didn’t find any.

But it looks possible to do using things like parseHTML(), [URL=“http://api.jquery.com/index/”]index(), [URL=“http://api.jquery.com/find/”]find(), etc.

I guess the first thing is to determine what to expect in the source strings. Are they of different lengths but always the same sequence of the same HTML elements?

Here’s a simple demo that shows the problem of the output:

Comment shown before the more link is clicked…

Comment shown after the more link is clicked…

From your question above, I think as the user can input anything, it could be in different length and different sequence in the same HTML element.

I’m more interested in knowing what HTML tags are in the string you need to parse <a> anchors only?

In my case, the content of the <p> element are all queried from the database.

<p id ="content" class="minimize" style ="border-radius: 4px 4px 4px 4px; max-width :500px; min-height :5px; margin-left :65px; display :block; background-color: #CCCCFF;" > <%# DataBinder.Eval(Container.DataItem,"Comments").ToString() %> </p> 

Since all the data that are displayed in the <p> element are user inputs that were saved from the database then I’m
presumptous that the content inside the <p> element are all pure strings and <a>link</a>. Try to imagine this tag as it displays. Hope this gives clue for you…

<p>string string string string <a>link</a> string string string <a>link</a> string string string </p>

If it’s always going to be only text and links inside of p tags it should be easy enough.

You’ll need to decide what the absolute maximum allowable length can be.
Then maybe something like this might work (not tested)

var max_str_length = 126; // or whatever
var max_found_index = 0;
$( 'p' )
  .html()
  .find( 'a' )
  .each(function() {
    if ( ( $(this).index() <  max_str_length ) && ( $(this).index() >  max_found_index ) ) {
      max_found_index = $(this).index();
    }
  });

Then you can use max_found_index in the slice()

I think this is close to the right code for the right output. So I tried to apply that code given above to my original jquery code but I’m not sure if I did the right modification since I’m still new to this language so it turned out something like this…

Modified code:

$(function(){

var minimized_elements = $('p.minimize');

var max_str_length = 126; // or whatever
var max_found_index = 0;
$('p.minimize')
  .html()
  .find('a')
  minimized_elements.each(function() 
  {
  var t = $(this).text(); 
  if(t.length < max_str_length) return; 
      
        if ( ( $(this).index() <  max_str_length ) && ( $(this).index() >  max_found_index ) )
         {
       max_found_index = $(this).index();
       $(this).html(
      
           t.slice(0,max_str_length) + '<span class="showcontent" ></span><a href="#" class="more">...More</a>'+ 
            '<span style="display:none;">'+ t.slice(max_str_length,t.max_found_index) +' <a href="#" class="less">Less</a></span>'            
        );
  }
  
  });

$('a.more', minimized_elements).click(function(event){
       
        event.preventDefault();
        $(this).hide().prev().hide();     
        $(this).next().show(); 
      
                    
    });
    
    $('a.less', minimized_elements).click(function(event){
      
        event.preventDefault();
        $(this).parent().hide().prev().show().prev().show();         
      
    });

});

but it gives me more complicated output than before which shows like this…

I believe I made mistakes on modifying my codes. Can you help me modify that code in a right way using your sample code?
Thanks a lot for this walkthrough I really appreciated this.

text() = plain text.
html() = HTML

Maybe it will work using
var t = $(this).html();
instead, or you can force it back to HTML somehow before showing it?

I tried to use var t = $(this).html(); but still giving same output. I’m not sure if I did the right data structuring or algorithm in my code. I guess on this kind of scenario is not possible for jquery but I was wondering why FB’s comment options and status updates are perfectly programmed in which even if you attached any links in any of your paragraph and goes beyong their limits then it will automatically generates 'See more" link without ruining any links inside the paragraph. I think FB uses another techniques for this besides jquery.