I've just implemented the quotes module and really like it...the only thing I would like to see changed is have an option to limit the length of the single quote displayed in the block. We would specify the number of words wanted in the admin section or specifically for each created block and then it would just add ellipses to the end of the quote if it exceeded the given length and had to be cropped.
I'm probably going to figure out how to do this myself, but it would be nice to have from the start.

Comments

jhriggs’s picture

I think the idea is that quotes are short, so this wasn't necessary. In theory, this is the case, but in practice, I have seen some pretty long quotes. I suppose this could be handled with Drupal's standard teaser-handling. That is, a block would show the teaser with a 'read more' link, but the node's page and the 'quotes'/'my quotes' pages would show the full quote.

Thoughts?

heine’s picture

/**
 * Truncates $text to near $size, but tries to find sentence / word borders
 *
 * @param $text
 *   The text to truncate
 * @param $size
 *   Desired length 
 * @param $ensure_limit
 *   when TRUE  - ensures returned text smaller then $text_length (default)
 *   when FALSE - similar behaviour as node teaser, may be larger then $text_length
 * 
 * Note remove ' ' => from the array in the if($ensure_limit) clause to always truncate on sentence borders 
 */
function custom_truncate_text($text, $size, $ensure_limit = FALSE) {
  // If short enough, do nothing.
  if (strlen($text) < $size) {
    return $text;
  }
  
  if($ensure_limit) {
    // We have to stay within limits, but don't want to truncate within a word   
    $max_text = truncate_utf8($text, $size);
    
    // Remove ' ' => 0 from the array, to always truncate at sentence borders.
    $breakpoints = array(' ' => 0, "\n" => 0, '. ' => 1, '! ' => 1, '? ' => 1, '。' => 3, '؟ ' => 1);
    foreach ($breakpoints as $point => $charnum) {
      if ($length = strrpos($max_text, $point)) {
        return substr($text, 0, $length + $charnum);
      }
    }
    // If a space could not be found, be blunt 
    return truncate_utf8($text, $size);
  }
  
  $breakpoints = array("\n" => 0, '. ' => 1, '! ' => 1, '? ' => 1, '。' => 3, '؟ ' => 1);
  foreach ($breakpoints as $point => $charnum) {
    if ($length = strpos($text, $point, $size)) {
      return substr($text, 0, $length + $charnum);
    }
  }

  // If all else fails, we simply truncate the string.
  return truncate_utf8($text, $size);
}
  
heine’s picture

Contrary to the phpdoc, the default of ensure_limit is actually FALSE

jhriggs’s picture

If I implement a feature like this though, Heine, I am not going to re-code a lot of stuff like you suggest. Drupal already has built-in teaser-handling, so I will use what we already have. That way users can specify what should be included (by using <!--break--> for instance). Additionally, if they are using contrib modules like superteaser or excerpt, they will be used just like they are for other nodes.

heine’s picture

Sorry, my piece of code was directed at the OP, not a suggestion how to implement it in Quotes. It's actually mostly node_teaser, but the problem with node_teaser is that it doesn't ensure text smaller than the cut off size.

sokrplare’s picture

Thanks for the code Heine, the only issue is that I'm not sure how to work it into the quotes module so that it only takes affect for quotes that are displayed in a block. Do you, or anyone else, know how I can distinguish between quotes that will be displayed in a block and those displayed as a normal node? I tried to customize theme_quotes_quote, but that did it for every quote.

jhriggs, the issue with the normal teaser idea is that it is so long. I've got a really limited space for the quote in this design so I have to cut it off at way fewer than the teaser's lowest setting of 200 chars. Also, for most node types I want the teaser to be much longer - so I would prefer to be able to set it individually for the quotes module and then use the normal teaser setting for all other posts. Like you said though, it would just be the block that has the teaser - everything else shows the full version. Is this possible?

nancydru’s picture

You could do it in "quotes_block" under "case: 'view'". You'll find $quote = quotes_view(node_load($block['vid'])). Between that statement and the return, truncate "$quote->body".

nancydru’s picture

I've been looking at lots of things here. The 6.x version of "node_teaser" is much improved and would do what is wanted here quite nicely with the addition of a simple setting for the block. So, IMHO, this should be a 6.x feature only.

nancydru’s picture

Also see the patch in http://drupal.org/node/136557

nancydru’s picture

Assigned: Unassigned » nancydru

@Heine: IMHO, that code should be in core. If it has not been proposed yet, please do. I may go ahead and stick it in the Helpers module any way.

The new 5.x-1.2 release does use the teaser now. I realize it doesn't fully meet the OP's needs, but it will be there in the 6.x release that I hope to have out tomorrow.

nancydru’s picture

Status: Active » Fixed

Fixed in 6.x-1.x-dev.

nancydru’s picture

Status: Fixed » Closed (fixed)
beautifulmind’s picture

Thanks a lot for this snippet.
It really works when you are not using any views but displaying body/teaser using a custom module.

Thank you very much.

Regards.